查找具有至少一个具有特定属性的子节点的节点的有效方法

时间:2019-02-23 12:27:59

标签: performance neo4j cypher

我有一个包含多个相关节点的图,我想找到所有具有至少一个带有相同名称和old_name的子标记为:B的标记为:A的节点。

节点总数为+ 6M:A节点和+ 60M:B节点(每个:B节点仅链接至一个:A节点,但每个:A节点均连接至n:B节点)

直到现在,我发现最有效的方法是找到正确的:B节点,然后将其与:A节点匹配,反之则更慢了

方法1

Match (b:B) 
where  b.val1<>b.val2 
with b
match (a:A)-[:Link]-(b)
return count(distinct a)
  

密码版本:CYPHER 3.5,计划程序:COST,运行时间:已编译。在3756615毫秒中,数据库总命中次数为155619605。

planner result method 1

方法2

Match (a:A)-[:Link]-(b:B)
where b.val1<>b.val2 
return count(distinct a)

结果:

  

密码版本:CYPHER 3.5,计划程序:COST,运行时间:已编译。在7122106毫秒中数据库总命中次数为155619605。

planner result method 2

如果我错了,请纠正我,但我认为遍历A节点(因为只有+ 6M)应该更快,而不是先找到一个满足条件的孩子:B,然后遍历相关:A节点。

2 个答案:

答案 0 :(得分:0)

筛选:B标记的节点,然后查找:A标记的节点会更快(您的第一种方法),因为我们有机会:大部分:B节点不满足条件,然后每个:B为仅连接到一个:A。

关于算法的效率:

至于您说每个:B节点仅连接到一个:A节点,我建议在每个:B节点上使用另一个属性来编写已连接的:A节点的ID。这样,您将在:B节点上仅剩一个循环,而在:A节点上的循环将被删除。

然后,您的代码将非常简单,如下所示:

Match (b:B) 
where  b.val1<>b.val2
return count(distinct b.aID)

答案 1 :(得分:0)

在您提供的查询计划中,两种情况下使用的计划完全相同。在这两种情况下,它都是从所有:A节点开始的,扩展了:LINK关系并进行过滤。两者之间唯一的不同是缓存的命中和未命中。

您将要确保您对其他可能的查询进行解释,以验证其执行方式,因为我们想了解如果首先从:B节点开始执行将是什么样子。我们需要强制执行此操作,因此我们可以先尝试使用scan hint

Match (b:B) 
using scan b:B
where  b.val1<>b.val2 
match (a:A)-[:Link]-(b)
return count(distinct a)

如果对此的解释是从对:B节点的标签扫描开始的,请继续进行分析,并查看其性能。