【问题标题】:Prefer node via direct connection over longer path首选通过直接连接而不是较长路径的节点
【发布时间】:2020-03-26 16:50:48
【问题描述】:

我的图模型应该允许从父级继承属性到子级,并覆盖子级继承的这些属性。属性是通过HAS 关系附加的节点。

CREATE (parent:Node {id: "P"})-[:HAS {inherited: true}]->(:Attribute:Name {value: "Indirect Name"})
CREATE (parent)-[:HAS]->(:Attribute:Other {value: "Other Attribute"})

CREATE (c1:Node {id: "C1"})-[:HAS]->(:Attribute:Name {value: "Direct Name"})
CREATE (c1)-[:BELONGS_TO]->(parent)
CREATE (c2:Node {id: "C2"})-[:BELONGS_TO]->(parent)

在这个例子中,我们有C1-[:BELONGS_TO]->PC2-[:BELONGS_TO]->PP 定义了一个被继承的属性Name 和一个不被继承的属性OtherC1 覆盖了Name 属性,而C2 继承了该属性。

我现在想查找属于某个节点的所有相关属性:C1 的直接附加名称属性和 C2 的间接名称属性。不应为 C1 和 C2 考虑“其他”属性,因为它不是继承的。

要获取所有直接和继承的属性,我可以使用以下查询:

MATCH (c {id: "C1"})-[:HAS]->(directAttribute:Attribute), (c)-[]->(:Node)-[:HAS{inherited: true}]->(inheritedAttribute:Attribute) RETURN directAttribute, inheritedAttribute

但这显然会返回Name 属性,一个来自C1 和继承自P。我们如何“更喜欢”直接附加到节点的属性而不是继承的属性,以便在这种情况下查询只返回“直接”名称属性?

【问题讨论】:

    标签: neo4j cypher graph-databases


    【解决方案1】:

    使用节点标签来区分属性名称对于您的用例来说非常笨拙。我建议将属性名称改为属性名称。例如,作为以下数据创建查询中的nameother(连同foo,以显示如何拥有多个继承属性):

    CREATE (parent:Node {id: "P"})-[:HAS {inherited: true}]->(:Attribute {name: "Indirect Name", foo: "Bar"})
    CREATE (parent)-[:HAS]->(:Attribute {other: "Other Attribute"})
    
    CREATE (c1:Node {id: "C1"})-[:HAS]->(:Attribute {name: "Direct Name"})
    CREATE (c1)-[:BELONGS_TO]->(parent)
    CREATE (c2:Node {id: "C2"})-[:BELONGS_TO]->(parent)
    

    然后,您可以使用便捷的 APOC 函数 apoc.map.merge 来获取 Node 的适用属性(注意将“直接”属性作为第二个参数传递)。

    例如,如果您将此查询用于“C1”:

    MATCH (c:Node {id: "C1"})
    OPTIONAL MATCH (c)-[:HAS]->(da:Attribute)
    OPTIONAL MATCH (c)-[:BELONGS_TO]->()-[:HAS {inherited: true}]->(ia:Attribute)
    RETURN c, apoc.map.merge(ia, da) AS attrs
    

    结果是:

    ╒═══════════╤══════════════════════════════════╕
    │"c"        │"attrs"                           │
    ╞═══════════╪══════════════════════════════════╡
    │{"id":"C1"}│{"name":"Direct Name","foo":"Bar"}│
    └───────────┴──────────────────────────────────┘
    

    对“C2”的相同查询得到这个结果:

    ╒═══════════╤════════════════════════════════════╕
    │"c"        │"attrs"                             │
    ╞═══════════╪════════════════════════════════════╡
    │{"id":"C2"}│{"name":"Indirect Name","foo":"Bar"}│
    └───────────┴────────────────────────────────────┘
    

    您可能还想使用不同的关系类型(例如,[:INHERITS])来代替 [:HAS {inherited: true}]

    【讨论】:

    • 谢谢,这是一个好的开始。当我添加另一个“父母”到例如C1 (C1)-[:BELONGS_TO]->(P2) 此查询多次返回具有不同属性集的 c。然后如何合并所有属性?
    • 顺便说一句:为什么标记不同类型的属性不适合这个用例?
    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 2022-01-21
    • 2014-03-05
    相关资源
    最近更新 更多