【问题标题】:How can I Limit nodes on each level of children in tree with cypher query如何使用密码查询限制树中每个子级的节点
【发布时间】:2021-08-05 07:43:22
【问题描述】:

我正在使用 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;

它返回给我整个树结构,我尝试用限制限制节点,但它不能正常工作

【问题讨论】:

    标签: neo4j cypher graph-theory


    【解决方案1】:

    我猜你必须先过滤掉路径。我的方法是确保路径中的所有子节点都在前一个 parent 的前 5 个子节点中。我没有准备好测试它的数据集,但它可能是这样的

    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
    

    另一种可能更快的方法是首先收集 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;
    

    更新

    数据的问题是树不是对称的,例如并非所有路径都具有相同的深度。例如节点 d0 没有子节点。因此,如果您在第一级选择五个孩子,您可能不会更深入。

    我添加了一种稍微不同的方法,它应该适用于对称树,并且允许您设置每个节点的最大子节点数。用 3 试试,你会发现你只从第一层得到节点。用 8 你得到更多。

    // 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
    

    【讨论】:

    • 为了创建数据集,你可以使用这个密码 CREATE (r:Person {id: 0, name: '00'}) FOREACH (i IN range(1,5)| CREATE (r)-[ :PARENT_OF]->(c:Person { id:i, name: 'd'+i})); MATCH (c:Person) FOREACH (j IN range(1,5)| CREATE (c)-[:PARENT_OF]->(:Person { id:c.id*10+j, name: 'a'+c. id*10+j })); MATCH (c:Person) FOREACH (j IN range(1,5)| CREATE (c)-[:PARENT_OF]->(:Person { id:c.id*10+j, name: 'd'+c. id*10+j }));
    • 我已经尝试过你的解决方案,但它不适用于我的用例......我真正想要实现的是为每个第一级孩子获得第一个 5 级孩子和五个五个孩子等等
    • 非常感谢您帮助我
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 2017-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    相关资源
    最近更新 更多