我正在尝试找到一种有效的方法来获取节点祖先的一组属性值。考虑以下简单的设置:
CREATE
(a {id:'a'}), (b {id:'b'}), (c {id:'c'}), (d {id:'d', age:10}),
(b)-[:HAS_PARENT]->(a),
(c)-[:HAS_PARENT]->(a),
(d)-[:HAS_PARENT]->(b),
(d)-[:HAS_PARENT]->(c)
我想在d
和d
之间以及a
的其他一些属性中获取ID为d
且所有ID的所有ID的集合}。
我想出了这个:
MATCH (d {id:'d'})
OPTIONAL MATCH path=(d)-[:HAS_PARENT*]->()
RETURN d.age as age,
(REDUCE(o = [], r IN (collect (extract (n in nodes(path) | n.id))) | o + r)) AS closure
哪个方法不起作用,因为它不会使closure
中的值保持唯一,而且效率也非常低效。如果我不使用此路径匹配,而只是将d
的ID设置为项目,然后使用Java API自行执行相同的遍历:
for (Path path: graphDb.traversalDescription()
.depthFirst()
.relationships(RealtionshipNames.HAS_PARENT, Direction.OUTGOING)
.uniqueness(Uniqueness.NODE_GLOBAL)
.traverse(graphDb.getNodeById(nodeId))) {
ids.add((String)path.endNode().getProperty("id"))
}
即使使用更大的数据集(100k节点,200k关系),任务也会在几秒钟内完成。通过我的Cypher查询,它永远不会完成。
有没有办法将这一切合并到一个高效的Cypher查询中,还是我最好用Java API进行一些后期处理?
答案 0 :(得分:2)
如果您现在只想要父母的身份证件:
MATCH (d {id:'d'})
OPTIONAL MATCH path=(d)-[:HAS_PARENT*]->(p)
WHERE NOT (p)-[:HAS_PARENT]->()
RETURN d.age, d.id, collect(NODES(path))
WHERE NOT (p)-[:HAS_PARENT]->()
只会将路径一直返回到第一个祖先,而不是中间路径。
对于从d到head祖先的树中的每条路径,这将返回一行,我认为这不是你想要的。您可以将其与UNWIND
结合使用WITH
语句将唯一ID提取到集合中。
如果你想要的只是那些没有真正关心路径的ID,你可以使用:
MATCH (d { id:'d' })
OPTIONAL MATCH path=(d)-[:HAS_PARENT*]->(p)
RETURN d.id, d.age, COLLECT(DISTINCT p.id)
如果你需要集合中的头部,那么将最后一行改为:
RETURN d.id, d.age, d+ COLLECT(DISTINCT p.id)