如何使用多节点匹配优化Neo4j Cypher查询(笛卡尔积)

时间:2014-06-26 18:08:29

标签: graph neo4j query-optimization cypher cartesian-product

我目前正在尝试合并三个数据集以进行分析。我正在使用某些常用字段来建立数据集之间的连接。为了创建连接,我尝试使用以下类型的查询:

MATCH (p1:Person),(p2:Person)
WHERE p1.email = p2.email AND p1.name = p2.name AND p1 <> p2 
CREATE UNIQUE (p1)-[IS]-(p2);

可以类似地写成:

MATCH (p1:Person),(p2:Person {name:p1.name, email:p1.email})
WHERE p1 <> p2 
CREATE UNIQUE (p1)-[IS]-(p2);

毋庸置疑,对于具有大约100,000个Person节点的数据库,这是一个非常慢的查询,特别是假设Neo4j不并行处理单个查询。

现在,我的问题是在Neo4j中是否有更好的方法来运行此类查询。我有至少8个CPU内核专门用于Neo4j,只要单独的线程不会通过锁定彼此来保持联系。所需资源。

问题在于我不知道Neo4j如何构建其Cypher执行计划。例如,我们说我运行以下测试查询:

MATCH (p1:Person),(p2:Person {name:p1.name, email:p1.email})
WHERE p1 <> p2 
RETURN p1, p2
LIMIT 100;

尽管有LIMIT条款,Neo4j仍然需要相当长的时间来交付结果,这让我想知道即使是这样一个有限的查询,Neo4j在考虑LIMIT语句之前是否产生了整个笛卡尔积表。

我感谢任何帮助,无论是解决这个特定问题,还是让我了解Neo4j一般如何构建Cypher执行计划(以及如何优化查询)。遗留的Lucene索引可以在这里提供任何帮助吗?

1 个答案:

答案 0 :(得分:8)

您可以对p1进行标签扫描,然后对p2进行索引查找+比较:

见这里:

cypher 2.1 
foreach (i in range(1,100000) | 
  create (:Person {name:"John Doe"+str(i % 10000),
                   email:"john"+str(i % 10000)+"@doe.com"}));
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 100000
Properties set: 200000
Labels added: 100000
6543 ms
neo4j-sh (?)$ CREATE INDEX ON :Person(name);
+-------------------+
| No data returned. |
+-------------------+
Indexes added: 1
28 ms

neo4j-sh (?)$ schema
Indexes
  ON :Person(name)  ONLINE

neo4j-sh (?)$ 
match (p1:Person) with p1 
match (p2:Person {name:p1.name}) using index p2:Person(name) 
where p1<>p2 AND p2.email = p1.email 
return count(*);
+----------+
| count(*) |
+----------+
| 900000   |
+----------+
1 row
8206 ms

neo4j-sh (?)$ 
match (p1:Person) with p1 
match (p2:Person {name:p1.name}) using index p2:Person(name) 
where p1<>p2 AND p2.email = p1.email
merge (p1)-[:IS]-(p2) 
return count(*);

+----------+
| count(*) |
+----------+
| 900000   |
+----------+
1 row
Relationships created: 450000
40256 ms