【发布时间】:2017-02-18 05:18:26
【问题描述】:
这是一个后续问题:
How to ask Neo4j to take cycles into account
在我之前的问题中,@stdob-- 好心帮我找到了以下查询:
MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)
OPTIONAL MATCH (n3t)-[:R]->(n4:R:L)
WHERE n3t = n3
RETURN labels(n1), labels(n3t), labels(n4);
上面的查询是以下查询的替换:
MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)-[:R]->(n4:R:L)
RETURN labels(n1), labels(n3t), labels(n4);
我必须使用第一个,因为在我的数据中,n2 和 n4 可能是相同的节点,并且由于 Neo4j 拒绝两次使用相同的节点,因此它将返回 null。
虽然第一个查询有效且有效,但它的性能非常糟糕。它强制数据库重新开始搜索整个数据,最后,它将使用n3t = n3 匹配选定的节点。只是为了给你一个关于它的性能有多糟糕的提示,在一个 200k 大小的数据集上,返回结果需要 5 秒,而如果我省略第二个 OPTIONAL MATCH 和它的 WHERE,结果会在不到 10相同查询的毫秒数。如果有人感兴趣,这里是查询的执行计划:
右分支是我前面提到的部分(我试图欺骗Neo4j第二次取一个节点)。如您所见,为了使 Neo4j 第二次获取节点,产生了 2M 的数据库命中。这个执行计划的实际查询是:
PROFILE MATCH (n5_1:Revision:`Account`)<-[:RevisionOf]-(n5_2:Entity:`Account`)
WITH n5_2, n5_1
ORDER BY n5_1.customer_number ASC
LIMIT 100
OPTIONAL MATCH (n5_1)-[:`Main Contact`]->(n4_1:Wrapper)<-[:Wrapper]-(:Revision:`Contact`)<-[:RevisionOf]-(n4_2:Entity:`Contact`)
OPTIONAL MATCH (n4_4)-[:RevisionOf]->(n4_3:Revision:Latest:`Contact`:Active)
WHERE (n4_2) = (n4_4)
RETURN n5_1, n5_2, n4_1, n4_2, n4_3
所以我的问题是,我如何编写一个 Cypher 查询,其中第二次获取一个节点而性能不会受到影响?
对于一些示例数据和测试平台,请转到另一个问题。
【问题讨论】:
-
您是否考虑过为此编写自定义程序?您可能希望查看 APOC 的 PathExplorer 的代码作为起点。这将使您能够更好地控制遍历唯一性,允许您在遍历期间重用边。
-
您的最后一个 OPTIONAL MATCH 有点奇怪,因为您在这里使用了一个新变量
n4_4,但是您在说它必须等于n4_2之后有一个 where 子句。此可选匹配是您的性能下降的原因。如果你在这场比赛中使用n4_2,它应该可以工作。但是,在您的链接问题中,这产生了一些不良结果,但看起来应该很容易过滤您必须确保n_43不为空的结果。