neo4j - 如何使用密码查询限制树中每个子级的节点
问题描述
我正在使用 cypher 和 neo4j 我有一个很大的父子关系数据集
(:Person)-[:PARENT_OF*]-(:Person)
我需要在树的每一级上获得只有 5 个孩子(节点)的家谱
我试过了:
MATCH path = (jon:Person )-[:PARENT_OF*]-(:Person)
WITH collect(path) as paths
CALL apoc.convert.toTree(paths) yield value
RETURN value;
它返回给我整个树结构,我尝试用限制限制节点,但它不能正常工作
解决方案
I guess you have to filter out the paths first. My approach would be to make sure that all children in the path are among the first 5 child nodes of the previous parent . I don't have a dataset ready to test it, but it could be along the lines of this
MATCH path = (jon:Person )-[:PARENT_OF*]->(leaf:Person)
// limit the number of paths, by only considering the ones that are not parent of someone else.
WHERE NOT (leaf)-[:PARENT_OF]->(:Person)
// and all nodes in the path (except the first one, the root) be in the first five children of the parent
AND
ALL(child in nodes(path)[1..] WHERE child IN [(sibling)<-[:PARENT_OF]-(parent)-[:PARENT_OF]->(child) | sibling][..5])
WITH collect(path) as paths
CALL apoc.convert.toTree(paths) yield value
RETURN value
another approach, perhaps faster, would be to first collect all the first five children of descendants of jon
// find all sets of "firstFiveChildren"
MATCH (jon:Person { name:'jon'}),
(p:Person)-[:PARENT_OF]->(child)
WHERE EXISTS((jon)-[:PARENT_OF*]->(p))
WITH jon,p,COLLECT(child)[..5] AS firstFiveChildren
// create a unique list of the persons that could be part of the tree
WITH jon,apoc.coll.toSet(
apoc.coll.flatten(
[jon]+COLLECT(firstFiveChildren)
)
) AS personsInTree
MATCH path = (jon)-[:PARENT_OF*]->(leaf:Person)
WHERE NOT (leaf)-[:PARENT_OF]->(:Person)
AND ALL(node in nodes(path) WHERE node IN personsInTree)
WITH collect(path) as paths
CALL apoc.convert.toTree(paths) yield value
RETURN value;
UPDATE
The issue with the data is that the tree is not symmetric, e.g. not all the paths have the same depth. node d0 for instance has no children. So if you pick five children at the first level, you may not be getting any deeper.
I added a slightly different approach, that should work with symmetric trees, and which allows you to set the number max number of children per node. Try it with 3, and you will see that you only get nodes from the first level., with 8 you get more.
// find all sets of "firstChildren"
WITH 8 AS numberChildren
MATCH (jon:Person { name:'00'}),
(p:Person)-[:PARENT_OF]->(child)
WHERE EXISTS((jon)-[:PARENT_OF*0..]->(p))
WITH jon,p,COLLECT(child)[..numberChildren] AS firstChildren
// create a unique list of the persons that could be part of the tree
WITH jon,apoc.coll.toSet(
apoc.coll.flatten(
[jon]+COLLECT(firstChildren)
)
) AS personsInTree
MATCH path = (jon)-[:PARENT_OF*]->(leaf:Person)
WHERE NOT (leaf)-[:PARENT_OF]->(:Person)
AND ALL(node in nodes(path) WHERE node IN personsInTree)
WITH collect(path) as paths
CALL apoc.convert.toTree(paths) yield value
RETURN value
推荐阅读
- java - Java WorldWind 表面形状导致渲染伪影
- ffmpeg - 使用 avformat 的分段 mp4 广播
- wordpress - 带有木材/树枝的 WordPress ACF 中继器
- javascript - 某些用户的值未定义,其他用户为空字符串
- node.js - 从 Heroku 帐户获取应用程序的 JSON 列表
- python - 垂直整合超过 1500 列的数据表
- java - 使用 Dropwizard 提供多个静态资产
- javascript - 正则表达式在两个字符串之间查找字符串
- less - 为组件定义css模块时如何访问antd less变量?
- javascript - CSS动画突然结束