tl;dr
在 Cypher 中不可能有无限循环,因此图表中的此类循环不会单独对查询性能造成问题。
详细的答案
这是一个很好的问题,答案的开头在uniqueness within Cypher traversals的文档中:
在模式匹配时,Neo4j 确保不包括在单个模式中多次找到相同图形关系的匹配项。在大多数用例中,这是明智的做法。
虽然这样说会更准确:
在单个路径
中多次找到相同的图关系
由于路径是根据匹配模式遍历的,因此特定关系可能只在该路径中遍历一次。遍历的方向在这里无关紧要。关系是否具有分配给它的变量或者关系是否是可变长度路径的一部分也没有。一旦一个关系被遍历了一条路径,它将永远不会被再次遍历。
这几乎可以保护您免受无限循环的影响,根据定义,无限循环要求您一遍又一遍地遍历相同的关系。
但是,当节点之间存在大量多条路径时,这并不能保护您免受成本上升的影响,因为可以遍历所有可能的关系(所有可能的关系都是唯一的并且从不重复每条路径)。
例如,如果您在 Neo4j 浏览器中从 :play movies 获取电影图,您可以发出类似 MATCH (n:Person)-[*]-(m:Person) RETURN count(*) 的查询,这可能永远不会返回,因为任意两个 :Person 节点之间可能的路径数,由于可以遍历的所有可能关系的排列(而不在每个单独的路径中重复任何关系)变得非常昂贵(并且这是针对图中两个 :Person 节点的所有可能组合完成的)。
这种类型的查询最终会锁定 Neo4j,因为要评估的路径数量达到天文数字,但这也不是由于无限循环。
要绕过这些限制(毕竟,您可能希望使用非常相似的查询来查找可访问的不同节点或可访问的不同节点的数量),您需要从 Cypher 的 ' 中更改遍历的唯一性RELATIONSHIP_PATH' 对其他事物的独特性。
如果您在 Java 中使用 Traversal Framework(如果您正在创建用户定义的过程、内核扩展或使用嵌入式 Neo4j,则可以使用该框架),您可以将 uniqueness of the traversal 更改为不同的行为。
关于避免无限循环,“NODE_PATH”的唯一性也将阻止它们,因为它确保每个单独的路径只能访问一个节点。
防止无限循环的最有用的方法之一是“NODE_GLOBAL”唯一性,它确保一个节点总共在所有路径上只被访问一次,而不仅仅是每个路径。当您想要查找从起始节点可到达的所有不同节点(或计算所有不同节点)时,最好使用这种唯一性,因此我们在 APOC Procedures 的某些 path expander procs 内使用“NODE_GLOBAL”唯一性库(并且在使用 apoc.path.expandConfig() 时,如果您想要不同的类型,您可以自己显式设置唯一性)。
总而言之,默认情况下,使用 Cypher 不会发生无限循环。您遇到的一些更严重的 Cypher 性能问题可能与匹配匹配模式的可能路径数量激增有关,尤其是在无限可变长度扩展的情况下,因为这可能会占用堆空间或以其他方式发展为非常高的数量独特的评估路径。通过遍历 API 或 APOC 路径扩展程序,您可以根据查询的需要更改遍历唯一性行为。