Neo4j Cypher最低共同祖先表现问题

时间:2016-02-23 11:13:31

标签: neo4j cypher lowest-common-ancestor

我正在尝试使用graphrepository在spring-neo4j中创建一个应用程序。 其中一个要求是在两个子节点之间找到最低公共祖先(lca)。

目前我使用以下查询来实现此目的:

 @Query("MATCH path = (c1:Concept)-[r:Relation*{type: 'Is a'}]->(ca:Concept)<-[r:Relation*{type: 'Is a'}]-(c2:Concept) 
      WHERE c1.conceptID = {conceptId1} AND c2.conceptID = {conceptId2}
      RETURN ca ORDER BY length(path) LIMIT 1")

Concept findLowestCommonAncestor(@Param("conceptId1") Long conceptId1, @Param("conceptId2") Long conceptId2);

这里的问题是性能。最初我的图表由330 000个节点和2 000 000个关系组成。我感兴趣的关系是类型:“是一个”。它们仅在树中向上移动(将子节点与父节点连接)。最大向上距离为3。

这是树结构:

Tree structure example

因为我有几个像这样的树结构,所以我决定添加一个将所有不同树结构连接在一起的根节点。这样lca总能找到。但添加此根节点大大改变了我的性能: 从558毫秒到562286毫秒

我知道添加根节点会影响性能,但不应该这么多,对吧?如果是这样,有没有更好的方法来计算lca?

我认为我的密码查询只会在树中向上查找节点。因此,在这种情况下,添加额外的根节点不应该对性能产生太大影响。

2 个答案:

答案 0 :(得分:1)

首先,我要感谢@Supamiu对我提问的帮助。

虽然他的答案对某些案件来说可能已经足够了。在我的情况下,实际上不可能改变模型。

令人惊讶的是,我设法通过更改密码查询来提高性能。

我的原始查询:

MATCH path = (c1:Concept)-[r1:Relation*{type: "Is a"}]->(ca:Concept)<-[r2:Relation*{type: "Is a"}]-(c2:Concept)
WHERE c1.conceptID=35104066 AND c2.conceptID=35808913
RETURN ca
ORDER BY length(path)
LIMIT 1

个人资料:http://i.imgur.com/14yleCo.png

我把它改为:

MATCH (c1:Concept {conceptID: 35104066})-[:Relation*{type: "Is a"}]->(p1:Concept)
MATCH (:Concept {conceptID: 35808913})-[:Relation*{type: "Is a"}]->(p2:Concept)
WHERE p1.conceptID = p2.conceptID
MATCH path = (c1)-[:Relation*{type: "Is a"}]->(p1)
RETURN p1
ORDER BY length(path)
LIMIT 1

个人资料:http://imgur.com/YCDDF5H

这使我的最低共同祖先在100毫秒左右,显着改善!

我仍然不完全理解为什么会产生这样的差异。但我认为其中一个原因是我使用的是树形结构。我想在第二个查询中,Cypher只在树中向上搜索,导致搜索关系减少。因此,在blob结构中,我认为这不会有所帮助。

有人可以证实这一点吗?

答案 1 :(得分:0)

你的问题是一个关系标签问题,让我解释一下:

首先,您的请求与:Relation关系中的无限深度相匹配。

您说数据库中的每个树现在都与根节点相关,我猜它与使用:Relation关系的根节点相关。

因此,当您将标记为:Relation的每个关系与无限深度匹配时,它将匹配数据库中的每个关系,然后在type属性上进行过滤。这就是为什么这个根节点添加了这样一个perf问题,因为它以相同的关系连接每个节点。

如何解决这个问题?

更改关系标签,使用它们而不是与属性匹配:

(ca:Concept{properties...})-[:IS_A]->(ca2:Concept)

使用另一个关系标签将您的顶级树节点链接到根节点。

然后,当您使用无限深度请求匹配您的节点时,您将能够使用标签进行匹配,从而避免您实际遇到的问题。

另一个解决方案是在查询中添加深度最大值,因为您的树最多为3个级别,您可以将关系深度限制为3.但在我看来,第一种解决方案更好,因为只创建一种类型在neo4j中,使用属性进行关系和过滤是一种不好的做法。

修改

所以,这是您的第一个个人资料:http://i.imgur.com/xskg39J.png

你可以在这里看到匹配[:Relation*]在被过滤之前有31,328次点击,这非常好。

在第二个配置文件(带根节点)上:http://i.imgur.com/14yleCo.png

你可以看到相同的匹配得到近2,000,000次点击,经过过滤后,是500,000次......这太过分了。

我认为解决方案是Path,你可以看看这个:

只有&#34;更好的&#34;才能解决问题。密码查询。我认为您的问题可以通过更好的数据模型来解决,但是如果没有项目本身的工作,很难找到哪个问题。我能提供的唯一想法是指南:http://neo4j.com/developer/guide-data-modeling/