代码之家  ›  专栏  ›  技术社区  ›  tony_tiger

查找具有公共二级关系的节点的所有子树

  •  4
  • tony_tiger  · 技术社区  · 7 年前

    我正在neo4j数据库中处理物料清单(bom)和零件数据。

    我的图表中有三种类型的节点:

    • (ItemUsageInstance) 这些是物料清单树的元素
    • (Item) 一个存在于BOM树上的每个唯一项目
    • (Material)

    这些关系是:

    • (ItemUsageInstance)-[CHILD_OF]->(ItemUsageInstance)
    • (ItemUsageInstance)-[INSTANCE_OF]->(Item)
    • (Item)-[MADE_FROM]->(Material)

    图示如下:

    schema

    这是数据的简化图。(重新定位节点以增强可见性的关系图):

    enter image description here

    我想做的是找到相邻的子树 ItemUsageInstance 是谁的 Items 都是用同样的材料做的 Material s公司

    到目前为止,我的疑问是:

    MATCH (m:Material)
    WITH m AS m
    MATCH (m)<-[:MADE_FROM]-(i1:Item)<-[]-(iui1:ItemUsageInstance)-[:CHILD_OF]->(iui2:ItemUsageInstance)-[]->(i2:Item)-[:MADE_FROM]->(m) RETURN iui1, i1, iui2, i2, m
    

    但是,这只返回一个这样的子树,即图中间的相邻节点 材料 “M0002”此外,结果行是单独的条目,子树中的每个父子对对应一个条目:

    ╒══════════════════════════╤══════════════════════╤══════════════════════════╤══════════════════════╤═══════════════════════╕
    │"iui1"                    │"i1"                  │"iui2"                    │"i2"                  │"m"                    │
    ╞══════════════════════════╪══════════════════════╪══════════════════════════╪══════════════════════╪═══════════════════════╡
    │{"instance_id":"inst5002"}│{"part_number":"p003"}│{"instance_id":"inst7003"}│{"part_number":"p004"}│{"material_id":"M0002"}│
    ├──────────────────────────┼──────────────────────┼──────────────────────────┼──────────────────────┼───────────────────────┤
    │{"instance_id":"inst7002"}│{"part_number":"p003"}│{"instance_id":"inst7003"}│{"part_number":"p004"}│{"material_id":"M0002"}│
    ├──────────────────────────┼──────────────────────┼──────────────────────────┼──────────────────────┼───────────────────────┤
    │{"instance_id":"inst7001"}│{"part_number":"p002"}│{"instance_id":"inst7002"}│{"part_number":"p003"}│{"material_id":"M0002"}│
    └──────────────────────────┴──────────────────────┴──────────────────────────┴──────────────────────┴───────────────────────┘
    

    我期待着第二个子树,它碰巧也是一个链表,被包括在内。第二个子树由 ItemUsageInstances 在图的最右边的STIM7000、STIM7000、STIM7000。值得一提的是,这些相邻的实例不仅是由同一个 材料 ,它们都是相同的实例 Item .

    我确认 项目使用说明 节点具有 [INSTANCE_OF] 项目 节点:

    MATCH (iui:ItemUsageInstance) WHERE NOT (iui)-[:INSTANCE_OF]->(:Item) RETURN iui 
    

    (返回0条记录)。

    也证实了 项目 节点具有 [MADE_FROM] 与A的关系 材料 节点:

    MATCH (i:Item) WHERE NOT (i)-[:MADE_FROM]->(:Material) RETURN i 
    

    (返回0条记录)。

    证实了 inst7008 是唯一的 项目使用说明 没有外向的 [CHILD_OF] 关系。

    MATCH (iui:ItemUsageInstance) WHERE NOT (iui)-[:CHILD_OF]->(:ItemUsageInstance) RETURN iui
    

    (返回1条记录: {"instance_id":"inst7008"} )

    inst5000 inst7001 是唯一的 项目用途说明 没有输入 [孩子的] 关系

    MATCH (iui:ItemUsageInstance) WHERE NOT (iui)<-[:CHILD_OF]-(:ItemUsageInstance) RETURN iui
    

    (返回2条记录: {"instance_id":"inst7001"} {"instance_id":"inst5000"} )

    我想收集/聚合结果,以便每一行都是子树我看到了 this example 如何 collect() 让数组方法起作用。但它仍然有复制品 项目使用说明 在里面。(此处讨论的“项目图”完全失败…)

    关于为什么我的查询只查找具有相同材质的相邻项使用实例的一个子树,有何见解?

    按子树汇总结果的最佳方法是什么?

    3 回复  |  直到 7 年前
        1
  •  1
  •   Tezra    7 年前

    寻根很容易。 MATCH (root:ItemUsageInstance) WHERE NOT ()-[:CHILD_OF]->(root)

    对于子对象,可以通过指定最小距离0(默认值为1)来包含根对象。

    MATCH p=(root)-[:CHILD_OF*0..25]->(ins), (m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(ins)

    然后假设每个实例只有一个item material,根据material聚合所有内容(不能聚合到聚合中,因此在使用节点收集深度之前使用with获取深度)

    WITH ins, SIZE(NODES(p)) as depth, m RETURN COLLECT({node:ins, depth:depth}) as instances, m as material


    所以,一起

    MATCH (root:ItemUsageInstance),
          p=(root)<-[:CHILD_OF*0..25]-(ins),
          (m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(ins)
    WHERE NOT ()<-[:CHILD_OF]-(root)
      AND NOT (m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-()<-[:CHILD_OF]-(ins)
    MATCH p2=(ins)<-[:CHILD_OF*1..25]-(cins)
    WHERE ALL(n in NODES(p2) WHERE (m)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(n))
    WITH ins, cins, SIZE(NODES(p2)) as depth, m ORDER BY depth ASC
    RETURN ins as collection_head, ins+COLLECT(cins) as instances, m as material
    
        2
  •  0
  •   FrobberOfBits    7 年前

    在你的模式中,你不考虑像inst_和inst_之间的链接这样的情况。inst_没有任何指向任何部分用法的链接,但是您的匹配模式要求两个用法都有这样的链接。我想这是你偏离轨道的地方。您找到的instúu5002树是因为它碰巧有一个链接指向您的模式所需的用法。

    在“按子树聚合”方面,我将返回树的根的ID(例如。 id(iui1) 然后 count(*) 其余的,显示给定根参与了多少子树。

        3
  •  0
  •   tony_tiger    7 年前

    以下是我经过大量编辑的查询:

    MATCH path = (cinst:ItemUsageInstance)-[:CHILD_OF*1..]->(pinst:ItemUsageInstance), (m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(pinst)
    WHERE ID(cinst) <> ID(pinst) AND ALL (x in nodes(path) WHERE ((x)-[:INSTANCE_OF]->(:Item)-[:MADE_FROM]->(m)))
    WITH nodes(path) as insts, m
    UNWIND insts AS instance
    WITH DISTINCT instance, m
    RETURN collect(instance), m
    

    它返回了我所期望的:

    ╒═════════════════════════════════════════════════════════════════════════════════════════════════════════════╤═══════════════════════╕
    │"collect(instance)"                                                                                          │"m"                    │
    ╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════╪═══════════════════════╡
    │[{"instance_id":"inst7002"},{"instance_id":"inst7003"},{"instance_id":"inst7001"},{"instance_id":"inst5002"}]│{"material_id":"M0002"}│
    ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
    │[{"instance_id":"inst7007"},{"instance_id":"inst7008"},{"instance_id":"inst7006"}]                           │{"material_id":"M0001"}│
    └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────┘
    

    一个限制是它不能区分子树的根和子树。理想情况下 {"instance_id"} 将按树的深度排序。