为什么这个Cypher查询需要花费太多时间?

时间:2015-03-16 19:04:35

标签: neo4j cypher

我有

  • 50K Post节点
  • 40K标记节点
  • 125K TAGGED关系(意味着每个帖子平均2,5个标签)

在我的图表和下面的查询中导致了一个" Java堆空间"错误。

match (p1:Post)-[r1:TAGGED]->(t:Tag)<-[r2:TAGGED]-(p2:Post)
return p1.Title, count(r1), p2.Title, count(r2)
limit 10

我期望的是一些重复的行,具体取决于共享标签的数量。我不确定limit将如何工作(在前10个帖子或标签后停止)。但是,因为我有limit 10我不希望这个查询遍历所有图形。看起来确实如此。

更新1

通过一些更改,Christophe Willemsen的查询在15秒内返回10行。

// I need label for the otherPost because Users are also TAGGED
MATCH (post:Post)-[:TAGGED]->(t)<-[:TAGGED]-(otherPost:Post) 
RETURN post.Title, count(t) as cnt, otherPost.Title
// ORDER BY cnt DESC // for now I do not need this
LIMIT 10;

我想&#34; ORDER BY&#34;子句可能导致遍历所有可能的路径,所以我删除了该条款,但它仍然是15秒。这也是15秒。当我在没有排序的情况下设定限值1或1000时。

我对Neo4j的期望是:&#34;从任何Post节点开始,然后跳转到其标签并找到标有相同标签的其他邮件。当有10个发现停止遍历并返回结果时。&#34;我很确定它没有这样做。

为了明确我的期望,假设图表很小,我们在密码查询中使用Limit 3

p1 - [t1, t2, t3] // Post1 is tagged with t1, t2 and t3
p2 - [t2, t3, t4]
p3 - [t3, t4, t5]

我的期望是:

  • 启动表单p1(或任何Post节点)
  • 跳至t1
  • 没有其他帖子标有t1
  • 跳至t2
  • p2标记为t2(1/3)
  • 没有其他帖子标有t2
  • 跳至t3
  • p2标记为t3(2/3)
  • p3标记为t3(3/3)
  • 我们达到了极限,打破了

但是,在遍历所有数据后似乎应用了限制。

所以,我现在的问题是:Neo4j是否找到了所有的比赛并返回其中的10个或者在前10场比赛后停止搜索?当然,为什么?

更新2

在得到有用的答案之后,我设法缩小了我的问题的范围,所以我尝试了以下查询。

// 3 sec.
MATCH (p:Post)-[:TAGGED]->(t:Tag)
RETURN p.Title, count(t)
LIMIT 1; 

// 3 sec.
MATCH (p:Post)-[:TAGGED]->(t:Tag)
RETURN p.Title, count(t)
LIMIT 1000; 

// 100 ms.
MATCH (p:Post)-[:TAGGED]->(t:Tag)
RETURN p.Title, t.Name
LIMIT 1; 

// 150 ms.
MATCH (p:Post)-[:TAGGED]->(t:Tag)
RETURN p.Title, t.Name
LIMIT 1000;

所以,我仍然不知道为什么,但是,使用聚合方法(我尝试collect(t.Name)而不是count)打破了limit功能的预期(至少我的期望:)行为

2 个答案:

答案 0 :(得分:6)

此查询将导致全局图表查找,至少对于neo4j 2.1.7及更低版本。

我首先匹配节点,然后扩展路径

MATCH (post:Post)
MATCH (post)-[:TAGS]->(t)<-[:TAGS]-(otherPost)
RETURN post, count(t) as cnt, otherPost
ORDER BY cnt DESC
LIMIT 10;

这是执行计划,正如您可以看到的那样,首先只匹配帖子节点(所以标签索引),只需要检索那些和以下关系

ColumnFilter
  |
  +Top
    |
    +EagerAggregation
      |
      +Filter
        |
        +SimplePatternMatcher
          |
          +NodeByLabel

+----------------------+--------+--------+----------------------------------------------+------------------------------------------------------------------------------------------------+
|             Operator |   Rows | DbHits |                                  Identifiers |                                                                                          Other |
+----------------------+--------+--------+----------------------------------------------+------------------------------------------------------------------------------------------------+
|         ColumnFilter |     10 |      0 |                                              |                                                              keep columns post, cnt, otherPost |
|                  Top |     10 |      0 |                                              | {  AUTOINT0}; Cached(  INTERNAL_AGGREGATEc24f01bf-69cc-4bd9-9aed-be257028194b of type Integer) |
|     EagerAggregation |   9900 |      0 |                                              |                                                                                post, otherPost |
|               Filter | 134234 |      0 |                                              |                                                                NOT(  UNNAMED30 ==   UNNAMED43) |
| SimplePatternMatcher | 134234 |      0 | t,   UNNAMED43,   UNNAMED30, post, otherPost |                                                                                                |
|          NodeByLabel |    100 |    101 |                                   post, post |                                                                                          :Post |
+----------------------+--------+--------+----------------------------------------------+------------------------------------------------------------------------------------------------+

Total database accesses: 101

这里有一篇博客文章,解释了除了查询的第一部分之外我删除标签的原因:http://graphaware.com/neo4j/2015/01/16/neo4j-graph-model-design-labels-versus-indexed-properties.html

答案 1 :(得分:2)

Christophe说 尽量减少两者之间的基数:

match (p1:Post)-[r1:TAGGED]->(t:Tag)
WITH tag, count(*) as freq, collect(distinct p1.Title) as posts
MATCH (tag)<-[r2:TAGGED]-(p2:Post)
return posts, freq, p2.Title, count(r2)
limit 10