NEO4J在做节点数量统计时运行非常慢
发布于 13 天前 作者 byuansh 71 次浏览 来自 问答

我们在Neo4j 3.3.0 版本上做了一轮测试,场景是有150万个节点(Label=Person)与79个分类树关联,这79个树是1-3级不等,共有1400万个关系。按照2-3个分类树中的2级节点统计与这2-3个分类树都关联到Person节点的数量,发现非常慢,需要400多秒才能跑出来。请前辈指点下,该如何调整比较好呢?

分类树的树形结构例如:

(A:CTN)-[:IS_PARENT]->(A1:CTN)-[:IS_PARENT]->(A11:CTN)
(A:CTN)-[:IS_PARENT]->(A1:CTN)-[:IS_PARENT]->(A12:CTN)
(A:CTN)-[:IS_PARENT]->(A2:CTN)-[:IS_PARENT]->(A21:CTN)
(A:CTN)-[:IS_PARENT]->(A2:CTN)-[:IS_PARENT]->(A22:CTN)
(A:CTN)-[:IS_PARENT]->(A3:CTN)
(A:CTN)-[:IS_PARENT]->(A4:CTN)
(B:CTN)-[:IS_PARENT]->(B1:CTN)

150个(Person)节点则可以与上面的树任意某个节点关联上,表示为 (Person) -[:MATCH]->(n:CTN) 的关系,合计1400万个关系。我们的查询语句则如下。它查找与在一级节点名称为A、B、C的分类树都关联上的(Person),然后按照这3个分类树的2级节点统计人数。我们在CTN节点的name字段上是有索引的。

MATCH path1=(d:DOC)-[:MATCH]->(p1n3:CTN)<-[:IS_PARENT]-(p1n2:CTN)<-[:IS_PARENT]-(p1n1:CTN), 
	path2=(d)-[:MATCH]->(p2n3:CTN)<-[:IS_PARENT]-(p2n2:CTN)<-[:IS_PARENT]-(p2n1:CTN),
	path3=(d)-[:MATCH]->(p3n3:CTN)<-[:IS_PARENT]-(p3n2:CTN)<-[:IS_PARENT]-(p3n1:CTN)
where p1n1.name = "A" and p2n1.name = "B" and p3n1.name = 'C'
	and p1n2.name in ['A1', 'A2', 'A3'] 
with p1n2, p2n2, p3n2, count(distinct d) as c
RETURN p1n2.name, p2n2.name, p3n2.name, c
order by p1n2.name, p2n2.name

上述查询用 profile 跑出来的结果大概如下,db hits 非常高,跑了400多秒。 Cypher version: CYPHER 3.3, planner: COST, runtime: INTERPRETED. 3,9498,830 total db hits in 43508 ms

以上结果是在一台E5-2675 1.8G,32G内存,SSD存储和Window 2008 R2服务器上测试的。

3 回复

有几个建议: 1、使用WITH,提前筛选出顶层节点: MATCH (p1n1:CTN {name:‘A’}), (p2n1:CTN {name:‘B’}), (p3n1:CTN {name:‘C’}) WITH p1n1, p2n1, p3n1 // 进行第2层及以下的查询 … …

  1. 对CTN.name建立索引
  2. 反过来写MATCH,既从CTN找DOC: MATCH (p1n1) -[:IS_PARENT]->(p1n2)->… <-[:MATCH]- (d:DOC)

@graphway 感谢你的回复,我们在 CTN 节点的name属性上是有索引的,上述查询一开始是通过 p1n1:CTN 和 p2n1:CTN 的索引找到1级节点了,所以,这与下面的查询是不是同等效果呢?

MATCH (p1n1:CTN {name:‘A’}), (p2n1:CTN {name:‘B’}), (p3n1:CTN {name:‘C’}) 
WITH p1n1, p2n1, p3n1

关于建议2,我们创建的也的确是 (d:DOC) -[:MATCH]-> (:CTN)节点的关系,所以,你的意思是建议我们改成:(d:DOC)<-[:MATCH]- (:CTN),这样反过来?

关于建议2,我的意思是从CTN出发找DOC。

回到顶部