我正在尝试使用以下Cypher查询计算Neo4j中无向图的传递闭包(" E"是图的每个边缘都有的标签):
MATCH (a) -[:E*]- (b) WHERE ID(a) < ID(b) RETURN DISTINCT a, b
我尝试在具有10k节点和大约150k边缘的图形上执行此查询,但即使在8小时后它也没有完成。我觉得这很令人惊讶,因为即使是最天真的SQL解决方案也要快得多,我预计Neo4j对于这些标准图形查询会更有效率。那么是否有一些我缺少的东西,可能是Neo4j服务器的一些调整或更好的编写查询的方式?
以下是EXPLAIN
上述查询的结果:
+--------------------------------------------+
| No data returned, and nothing was changed. |
+--------------------------------------------+
908 ms
Compiler CYPHER 3.3
Planner COST
Runtime INTERPRETED
+-----------------------+----------------+------------------+--------------------------------+
| Operator | Estimated Rows | Variables | Other |
+-----------------------+----------------+------------------+--------------------------------+
| +ProduceResults | 14069 | a, b | |
| | +----------------+------------------+--------------------------------+
| +Distinct | 14069 | a, b | a, b |
| | +----------------+------------------+--------------------------------+
| +Filter | 14809 | anon[11], a, b | ID(a) < ID(b) |
| | +----------------+------------------+--------------------------------+
| +VarLengthExpand(All) | 49364 | anon[11], b -- a | (a)-[:E*]-(b) |
| | +----------------+------------------+--------------------------------+
| +AllNodesScan | 40012 | a | |
+-----------------------+----------------+------------------+--------------------------------+
Total database accesses: ?
答案 0 :(得分:0)
您可以限制方向,但需要定向图表。
在对我自己进行一些测试和剖析之后,我发现即使是非常小的数据集(随机生成的10个节点的集合,每个节点上有2个随机边缘),使得查询仅针对单个方向减少数据库命中率为10000(从2266909到149数据库命中)。
为查询添加方向(从而强制图表被定向)会大大减少搜索空间,但需要指向图形。
我也试过为每个定向的一个添加一个反向关系,看看它是否会有类似的性能。它没;它在5分钟过去之前没有完成,此时我把它杀了。
不幸的是,您没有做错任何事,但您的查询量很大。
Neo4J是一个图形数据库并不意味着所有涉及图形的数学运算都会非常快;它们仍然受到性能限制,直至并包括传递闭包操作。
您编写的查询是对每一对节点的无限制路径搜索。节点对是有界的,但不是非常有意义的方式(ID(a)&lt; ID(b)的界限只意味着搜索只需要以一种方式完成;仍然有10k!(如在factorial中)结果集中可能的节点集。
然后,只有在检查了每条路径之后才会这样做。搜索图表的整个传递闭包,您指定的大小在性能方面将非常昂贵。
您发布的SQL未执行相同的操作。
您在评论中提到您在递归形式的关系表中尝试了此查询:
WITH RECURSIVE temp_tc AS (
SELECT v AS a, v AS b FROM nodes
UNION SELECT a,b FROM edges g
UNION SELECT t.a,g.b FROM temp_tc t, edges g WHERE t.b = g.a
)
SELECT a, b FROM temp_tc;
我应该注意,这个查询与Neo4J在尝试查找所有路径时所执行的操作并不相同。在Neo4J开始削减结果之前,它必须生成一个结果集,该结果集由整个图中的每个路径组成。
SQL和关系查询不会这样做;它从链接列表开始,但该递归查询具有删除任何潜在重复链接的效果;它发现其他链接是为了寻找他人的链接;例如如果图形看起来像(A) - (B) - (C),该查询将发现B在发现A连接到C的过程中连接到C.
使用Neo4J,必须单独发现每条路径。
如果这是您的一般用例,如果考虑速度,Neo4J可能不是一个好的选择。