为什么查找中间节点的查询需要这么长时间?
Why does the query to find intermediate nodes take so long?
数据库有一个包含以下 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 和 return 不同的节点。我认为,问题是它查询不同的路径,这意味着我也对它们之间的关系感兴趣。而实际上我对路径不感兴趣。我需要的只是与模式匹配的不同节点。我的理解是,如果我只能查询节点,查询路径会慢一些。
你能帮我理解我错过了什么吗?谢谢!
这可能是无界路径搜索?你真的想要两个节点之间任意长度的所有路径吗(例如跨越整个图的路径?)
这是你想要的吗?
MATCH(来源:App)
其中 origin.commit='10cb31b0a72525923c01dc34f8690f311a361d42'
MATCH(目标:App)
其中 destination.commit='51fde433973463f057ffcbcbab0bc8944ab3ec9c'
匹配(起点:App)-[:CHANGED_TO *0..1]->(intermediate_commit:App)-[:CHANGED_TO *0..1]->(目的地:应用程序)
RETURN 不同 intermediate_commit
我将路径长度限定为一跳,从 0.. 变为 0..1
(这意味着最少 0 个跃点,最多 1 个关系跃点)
模式和条件允许路径延伸过开始或结束节点但又进一步向下到达它们的可能性,这就是为什么它在找到一条匹配路径时不停止但继续扩展到它之外的原因。请记住,Cypher 关心的是找到满足图中存在的模式的所有可能路径。并且由于您的模式,无限制检查超越开始和结束节点不仅仅发生一次,而是在扩展时发现的每个潜在 (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 子句并仅匹配节点时,我们让 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 以匹配起点和终点也可以改进查询,如下所示:
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
数据库有一个包含以下 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 和 return 不同的节点。我认为,问题是它查询不同的路径,这意味着我也对它们之间的关系感兴趣。而实际上我对路径不感兴趣。我需要的只是与模式匹配的不同节点。我的理解是,如果我只能查询节点,查询路径会慢一些。
你能帮我理解我错过了什么吗?谢谢!
这可能是无界路径搜索?你真的想要两个节点之间任意长度的所有路径吗(例如跨越整个图的路径?)
这是你想要的吗?
MATCH(来源:App) 其中 origin.commit='10cb31b0a72525923c01dc34f8690f311a361d42' MATCH(目标:App) 其中 destination.commit='51fde433973463f057ffcbcbab0bc8944ab3ec9c' 匹配(起点:App)-[:CHANGED_TO *0..1]->(intermediate_commit:App)-[:CHANGED_TO *0..1]->(目的地:应用程序) RETURN 不同 intermediate_commit
我将路径长度限定为一跳,从 0.. 变为 0..1 (这意味着最少 0 个跃点,最多 1 个关系跃点)
模式和条件允许路径延伸过开始或结束节点但又进一步向下到达它们的可能性,这就是为什么它在找到一条匹配路径时不停止但继续扩展到它之外的原因。请记住,Cypher 关心的是找到满足图中存在的模式的所有可能路径。并且由于您的模式,无限制检查超越开始和结束节点不仅仅发生一次,而是在扩展时发现的每个潜在 (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 子句并仅匹配节点时,我们让 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 以匹配起点和终点也可以改进查询,如下所示:
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