Neo4j:使用CYPHER查找两个节点之间的所有路径的性能问题

时间:2015-04-24 17:19:11

标签: path neo4j cypher

我正在使用已下载here的TheMovieDB数据库。它有~60k节点和~100k关系,我需要在两个节点 a b 之间找到给定长度 k 的所有路径给定的名称属性。 让我们说我需要找到基努·里维斯 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 ,因为它不会返回任何长度大于较短路径的路径。

这让我发疯了...... 知道怎么解决吗?

修改

这个问题有多大的另一个例子:找到 Robert Downey Jr。 Harrison Ford 之间的长度路径4。 方法#2:~500毫秒 方法#1:> 360秒(在那6分钟之后,我残酷地拔掉了电源适配器)

1 个答案:

答案 0 :(得分:4)

你的第一个查询花了这么长时间的原因是因为它根本没有使用任何索引;您正在扫描整个数据库。

如果您稍微更改查询以在匹配的路径中包含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

您将看到查询计划明显不同。我认为简单地在关系中添加星号可能会将数据库引擎向下发送到不同的优化路径。

祝你好运!