如何使用连接提示避免代价高昂的遍历
使用 Cypher 匹配模式时,要评估的可能路径数量通常与查询执行时间相关。
当路径中存在超级节点(即具有大量关系的节点,其关系类型包含在您的 MATCH 模式中),或者仅仅是有足够多的具有许多关系的节点时,可能的路径数量会呈爆炸式增长,从而减慢您的查询速度。这种通过超级节点的遍历可能代价高昂。
有时,在遍历特定类型的模式时,您可能从建模中了解到,如果可能的话,为了获得最佳性能,两个特定类型的节点之间的关系应该以某个方向而非相反方向进行遍历,超级节点的情况通常如此。
例如,如果我们有一个由“人物” (:People) “喜欢” (:LIKE) 音乐艺术家组成的社交图,那么这些艺术家中的一些,甚至可能是很多,很可能就是超级节点。如果我们查看 (:Person)-[:LIKES]→(:Artist {name:'Britney Spears'})
,我们可以合理地假设一个“人物” (:Person) 可能具有相对较少的 :LIKES 关系,也许不到 100 个,但像 Britney Spears 这样受欢迎的“艺术家” (:Artist) 可能有数百万个指向她的 :LIKES 关系。
遍历通过 Britney Spears 将会代价高昂,因为它可能使可能的路径数量乘以 :LIKES 关系的数量,从而导致查询执行膨胀。然而,只遍历到 Britney Spears 的操作可能相对便宜。
在查询可能存在多个起始点,并且查询规划器在面对通过超级节点的不良遍历时无法提供高效计划的情况下,您可以在查询中使用连接提示来防止通过某个节点进行遍历。
取而代之的是,使用多个起始点,并从每个点进行扩展,直到到达连接提示中指定的节点。然后使用哈希连接来查找从两个方向匹配到的公共节点,并实现完全匹配的路径。
如果我想找出我和朋友共同喜欢的艺术家(以及共同喜欢的数量),我可能会有这样的查询:
MATCH (me:Person {name:'Me'})-[:FRIENDS_WITH]-(friend)-[:LIKES]->(a:Artist)<-[:LIKES]-(me)
RETURN a, count(a) as likesInCommon
如果规划器决定为此查询仅使用一个起始点,并且没有识别出潜在的超级节点问题,它可能会选择规划通过 :Artist 节点进行扩展,这可能代价非常高昂

由于 Cypher 查询规划器能够重新排列相邻 MATCH 模式(以及一些 WITH 子句)的顺序,仅仅重新排列我的模式是不够的。我可以使用连接提示来确保我们只遍历到目标节点,而不是通过它或远离它。
MATCH (me:Person {name:'Me'})-[:FRIENDS_WITH]-(friend)-[:LIKES]->(a:Artist)<-[:LIKES]-(me)
USING JOIN on a
RETURN a, count(a) as likesInCommon
从查询计划中我们可以看到,从相同的起始点,我们遍历了两条不同的路径,都指向 a
,但并未穿过它,并且执行了节点哈希连接,以在公共艺术家节点上统一这些路径。

此页面有帮助吗?