Neo4j:使用 CYPHER 查找两个节点之间的所有路径的性能问题
Neo4j: performance issue finding all paths between two nodes with CYPHER
我正在使用下载的 TheMovieDB 数据库 here。它有 ~60k 节点和 ~100k 关系,我需要找到两个节点 a 和 [=39] 之间给定长度 k 的所有路径=]b 与给定的 name 属性。
假设我需要找到 Keanu Reeves 和 Laurence Fishburne 之间所有长度为 2 的路径。我使用了以下 CYPHER 查询:
MATCH (k)-[e*2..2]-(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
用了 40 秒。
我决定尝试不同的方法并改用以下查询:
MATCH (k)--(m)--(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,m,l
用了 252 毫秒!
这两个查询给出了相同的结果,具有相同的含义,但第一个查询花费了 200 倍的时间。这怎么可能?
我需要进行一些测试,其中我必须找到两个给定节点之间具有给定最大(但不是最小)长度的所有路径。这给我带来了一些问题,因为我无法使用我描述的第二种方法(它仅适用于固定长度的路径)并且第一种方法太慢了。
我也不能使用 allShortestPath 因为它没有 return 任何长度大于较短路径的路径。
这让我发疯...
知道如何解决吗?
编辑
这个问题有多大的另一个例子:在 Robert Downey Jr. 和 Harrison Ford 之间找到一条长度为 4 的路径。
方法#2:~500 毫秒
方法#1:>360 秒(在那 6 分钟后我粗暴地拔掉了电脑电源适配器)
您的第一个查询花费这么长时间的原因是因为它根本没有使用任何索引;您正在扫描整个数据库。
如果您稍微更改查询以在您匹配的路径中包含 Actor
标签,您将显着提高查询性能。
MATCH (k)-[e*2..2]-(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
如果您通过在浏览器中执行 :schema
命令来显示索引,您将看到已存在的索引。可以看到第一个在:Actor(name)
;使用 Actor
标签,name
属性 被编入索引。
Indexes
ON :Actor(name) ONLINE
ON :Director(name) ONLINE
ON :Movie(title) ONLINE
ON :Person(name) ONLINE
ON :User(login) ONLINE (for uniqueness constraint)
Constraints
ON (user:User) ASSERT user.login IS UNIQUE
如果你profile
你的查询
profile
MATCH (k)-[e*2..2]-(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
然后分析添加了 :Actor
标签的那个,这将非常清楚为什么两者表现不同。
profile
MATCH (k:Actor)-[e*2..2]-(l:Actor)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
我忘了补充一点,您还应该 profile
您的第二个(更快的)查询:
profile
MATCH (k)--(m)--(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,m,l
您会发现查询计划明显不同。我认为简单地在关系中添加一个星号可能会使数据库引擎走上不同的优化路径。
祝你好运!
我正在使用下载的 TheMovieDB 数据库 here。它有 ~60k 节点和 ~100k 关系,我需要找到两个节点 a 和 [=39] 之间给定长度 k 的所有路径=]b 与给定的 name 属性。 假设我需要找到 Keanu Reeves 和 Laurence Fishburne 之间所有长度为 2 的路径。我使用了以下 CYPHER 查询:
MATCH (k)-[e*2..2]-(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
用了 40 秒。
我决定尝试不同的方法并改用以下查询:
MATCH (k)--(m)--(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,m,l
用了 252 毫秒!
这两个查询给出了相同的结果,具有相同的含义,但第一个查询花费了 200 倍的时间。这怎么可能?
我需要进行一些测试,其中我必须找到两个给定节点之间具有给定最大(但不是最小)长度的所有路径。这给我带来了一些问题,因为我无法使用我描述的第二种方法(它仅适用于固定长度的路径)并且第一种方法太慢了。
我也不能使用 allShortestPath 因为它没有 return 任何长度大于较短路径的路径。
这让我发疯... 知道如何解决吗?
编辑
这个问题有多大的另一个例子:在 Robert Downey Jr. 和 Harrison Ford 之间找到一条长度为 4 的路径。 方法#2:~500 毫秒 方法#1:>360 秒(在那 6 分钟后我粗暴地拔掉了电脑电源适配器)
您的第一个查询花费这么长时间的原因是因为它根本没有使用任何索引;您正在扫描整个数据库。
如果您稍微更改查询以在您匹配的路径中包含 Actor
标签,您将显着提高查询性能。
MATCH (k)-[e*2..2]-(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
如果您通过在浏览器中执行 :schema
命令来显示索引,您将看到已存在的索引。可以看到第一个在:Actor(name)
;使用 Actor
标签,name
属性 被编入索引。
Indexes
ON :Actor(name) ONLINE
ON :Director(name) ONLINE
ON :Movie(title) ONLINE
ON :Person(name) ONLINE
ON :User(login) ONLINE (for uniqueness constraint)
Constraints
ON (user:User) ASSERT user.login IS UNIQUE
如果你profile
你的查询
profile
MATCH (k)-[e*2..2]-(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
然后分析添加了 :Actor
标签的那个,这将非常清楚为什么两者表现不同。
profile
MATCH (k:Actor)-[e*2..2]-(l:Actor)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,e,l
我忘了补充一点,您还应该 profile
您的第二个(更快的)查询:
profile
MATCH (k)--(m)--(l)
WHERE k.name = "Keanu Reeves" AND l.name = "Laurence Fishburne"
RETURN k,m,l
您会发现查询计划明显不同。我认为简单地在关系中添加一个星号可能会使数据库引擎走上不同的优化路径。
祝你好运!