neo4j - 根据节点的排名限制查询

时间:2017-12-02 16:26:04

标签: neo4j cypher

我有一个节点的层次结构,它们都有一个自定义分配的排序属性(数字)。这是一个简单的Cypher查询来重新创建:

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 });

我正在努力解决的问题是,我经常需要根据相对于某个父节点的子节点等级做出决策,并重新指定此排序标识符。因此,例如,节点c1相对于节点p具有等级1(因为它具有最少sort属性),c2具有等级2和{{1}有排名3(最大的c3)。

我需要根据此信息做出的决定:仅显示前2个sort个节点的子节点。这就是我想要的:

graph

cXcc1存在,但cc2不是因为cc3(其父级)不是c3的第一个或第二个孩子。这是一个愚蠢的查询:

p

问题是,这些match (p {my_id: 1 })-->(c) optional match (c)-->(cc) where c.sort <= 200 return p, c, cc 属性是自定义设置和导入的,因此我无法知道将为2号子项保留哪个值。

我目前的解决方案是在导入期间对其进行排名,因为我使用的是Oracle,这非常简单 - 我只需要使用sort窗口函数。但这对我来说似乎很尴尬,我觉得可以有更优雅的解决方案。我尝试了下一个查询并且它可以工作,但它看起来很奇怪,而且在较大的图表上它很慢:

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 表达式:

query plan

1 个答案:

答案 0 :(得分: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