微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么查找中间节点的查询需要这么长时间?

如何解决为什么查找中间节点的查询需要这么长时间?

数据库一个包含以下 3 个节点的图:

...->(1) ------>(3)-->...
   \             ^
    \            |
     ---->(2)---/

现在,我想获取从节点 1 到节点 3 可到达的所有不同节点,包括我自己确切知道节点 1 和节点 3 的唯一属性的节点(这些节点实际上是从 github 存储库提交的)。所以,我想出了以下查询

MATCH (origin:App)
WHERE origin.commit='10cb31b0a72525923c01dc34f8690f311a361d42'
MATCH (destination:App)
WHERE destination.commit='51fde433973463f057ffcbcbab0bc8944ab3ec9c'
MATCH (origin)-[:CHANGED_TO*0..]->(intermediate_commit:App)-[:CHANGED_TO*0..]->(destination)
RETURN distinct intermediate_commit

但是,查询永远不会完成,或者至少需要很长时间才能完成。我知道我可以使用 MATCH p=(origin:App)-[:CHANGED_TO*0..]->(destination:App) 然后 UNWIND 并返回不同的节点。问题是,我相信,它查询不同的路径,这意味着我也对它们之间的关系感兴趣。虽然实际上我对路径不感兴趣。我需要的只是与模式匹配的不同节点。我的理解是查询路径比我只能查询节点时慢。

你能帮我理解我遗漏了什么吗?谢谢!

解决方法

那可能是无界路径搜索?你真的想要两个节点之间任意长度的所有路径(例如跨越整个图的路径?)

这符合您的要求吗?

MATCH(来源:App) WHERE origin.commit='10cb31b0a72525923c01dc34f8690f311a361d42' 匹配(目的地:应用程序) WHERE destination.commit='51fde433973463f057ffcbcbab0bc8944ab3ec9c' MATCH (origin:App)-[:CHANGED_TO *0..1]->(intermediate_commit:App)-[:CHANGED_TO *0..1]->(destination:App) RETURN不同的intermediate_commit

我将路径长度限制为一跳,从 0.. 变为 0..1 (这意味着最少 0 跳,最多 1 关系跳)

,

模式和条件允许路径延伸超过开始或结束节点但又向下到达它们的可能性,这就是为什么当它找到一个匹配的路径时它不会停止,而是继续扩展到它之外。请记住,Cypher 关注的是找到满足图中存在的模式的所有可能路径。由于您的模式,check-beyond-the-start-and-end-nodes-without-limit 不会只发生一次,而是根据扩展时发现的潜在 (intermediate_commit:App),这就是为什么您的查询不是'回来了。

获得所需内容的一种方法,所有可能的路径,但在到达节点时停止,是使用 APOC 路径扩展器,您可以将节点作为终止节点提供,这将停止通过它的进一步扩展。

MATCH (origin:App)
WHERE origin.commit='10cb31b0a72525923c01dc34f8690f311a361d42'
MATCH (destination:App)
WHERE destination.commit='51fde433973463f057ffcbcbab0bc8944ab3ec9c'
CALL apoc.path.expandConfig(destination,{relationshipFilter:'<CHANGED_TO',terminatorNodes:[origin]}) YIELD path
UNWIND nodes[path] as node
WITH DISTINCT node
WHERE node:App
RETURN node as intermediate_commit

这是从目的地向后扩展到起点,似乎这样可能更有效。一旦我们有了路径,我们就可以从所有路径中展开节点,保留不同的路径,并确保我们只获取 :App 节点。

,

解决方案非常简单。我们没有在 MATCH 子句中指定模式,而是将模式移到 WHERE 子句中。另外,我将模式分成两部分。我无法解释为什么它更快,但我的理解是,当我们将模式移动到 WHERE 子句和 MATCH only 节点时,我们让 neo4j 知道我们只对节点感兴趣,而不对匹配模式的所有可能路径感兴趣。

完整查询:

MATCH (origin:App)
  WHERE origin.commit='10cb31b0a72525923c01dc34f8690f311a361d42'
MATCH (destination:App)
  WHERE destination.commit='51fde433973463f057ffcbcbab0bc8944ab3ec9c'
MATCH (intermediate_commit:App)
  WHERE (origin)-[:CHANGED_TO*0..]->(intermediate_commit)
    AND (intermediate_commit)-[:CHANGED_TO*0..]->(destination)
RETURN distinct intermediate_commit

另外,如果你有很多节点,我相信指定 LIMIT 1 来匹配 origin 和 destination 也可以改进查询,就像这样:

MATCH (origin:App)
  WHERE origin.commit='10cb31b0a72525923c01dc34f8690f311a361d42'
WITH origin
LIMIT 1
MATCH (destination:App)
  WHERE destination.commit='51fde433973463f057ffcbcbab0bc8944ab3ec9c'
WITH origin,destination
LIMIT 1
MATCH (intermediate_commit:App)
  WHERE (origin)-[:CHANGED_TO*0..]->(intermediate_commit)
    AND (intermediate_commit)-[:CHANGED_TO*0..]->(destination)
RETURN distinct intermediate_commit

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。