2017-12-02 118 views
0

我有节点的分层结构,它们都具有一个自定义的分配排序属性(数字)限制查询。这里有一个简单的Cypher查询重现:的Neo4j - 基于节点的排名

merge (p {my_id: 1})-[:HAS_CHILD]->(c1 { my_id: 11, sort: 100}) 
merge (p)-[:HAS_CHILD]->(c2 { my_id: 12, sort: 200 }) 
merge (p)-[:HAS_CHILD]->(c3 { my_id: 13, sort: 300 }) 
merge (c1)-[:HAS_CHILD]->(cc1 { my_id: 111 }) 
merge (c2)-[:HAS_CHILD]->(cc2 { my_id: 121 }) 
merge (c3)-[:HAS_CHILD]->(cc3 { my_id: 131 }); 

我挣扎的问题是,我常常需要根据相对于一些父节点的子节点上排名的决定,与regads到这种标识。因此,例如,节点c1相对于节点p具有1级(因为它具有最小sort属性),c2具有等级2,并且c3具有等级3(最大sort)。

那种决定我需要根据这些信息:显示孩子只有前2个cX节点。这里就是我想:

graph

cc1cc2都存在,但cc3是不是因为c3(其父)不是第一或p的第二个孩子。下面是一个哑巴查询:

match (p {my_id: 1 })-->(c) 
optional match (c)-->(cc) where c.sort <= 200 
return p, c, cc 

问题是,这些sort属性自定义设置和进口的,所以我不知道哪个值将举行儿童数2.

的方式我目前的解决方案是在导入过程中的排名吧,因为我使用的是Oracle,这是很简单 - 我只需要使用rank窗口功能。但对我来说似乎很尴尬,我觉得可以有更优雅的解决方案。我试了下查询和它的作品,但它看起来奇怪,它在更大的图形非常慢:

match (p {my_id: 1 })-->(c) 
optional match (c)-->(cc) 
where size([ (p)-->(c1) where c1.sort < c.sort |c1]) < 2 
return p, c, cc 

下面是这个查询的计划和最昂贵的部分其实是在size表达:

query plan

回答

2

您看到的速度很慢很可能是因为您没有在查询中执行索引查找,所以它会执行所有节点扫描并访问图中每个节点的my_id属性以查找带有id的节点1(你的p节点)。

您需要在节点上的标签上添加标签,并在查询中使用这些标签(至少对你的p节点),并创建一个索引(或在这种情况下,很可能是唯一约束)为my_id所以这查找变得快速。

可以确认发生了什么事情,这样会在查询的个人资料(如果可以添加轮廓计划你的描述,具有扩展的计划,这将有助于确定进一步优化的所有元素)。

至于您的查询,这样的事情应该工作(我使用的是:节点标签为您的实际标号的替身)

match (p:Node {my_id: 1 })-->(c) 
with p, c 
order by c.sort asc 
with p, collect(c) as children // children are in order 
unwind children[..2] as child // one row for each of the first 2 children 
optional match (child)-->(cc) // only matched for the first 2 children 
return p, children, collect(cc) as grandchildren 

请注意,这只是返回的节点,而不是路径或关系。为什么你要在图形视图的结果曲线图的原因是,在浏览器的设置选项卡(在左下角菜单中的齿轮图标),你必须Connect result nodes底部检查。

+0

非常感谢您的扩大答复,我已经将剖析计划添加到我的问题。实际上,实际的DB需要索引和标签,正如您在计划中看到的那样,而计划中最昂贵的部分实际上就是具有大小的子句。话虽如此,你的查询是非常高效的,所以我会说这是诀窍!再次感谢! –