【问题标题】:How to "overlay" relationships using Neo4j?如何使用 Neo4j“叠加”关系?
【发布时间】:2021-03-28 23:38:40
【问题描述】:

我有一系列已售菜单项 (SMI) 节点(即在商店出售的项目)。在 SMI 下方列出了基本菜单项 (BMI),它们代表组成 SMI 的组件。例如,对于快餐,SMI 可能是套餐,而 BMI 可能是可乐、薯条和三明治。 SMI 节点为蓝色,BMI 节点为绿色。红色节点代表地理位置并有自己的层次结构(商店 -[inherits_from]-> 地区 -[inherits_from]-> 市场)。

SMI/BMI 层图:

我要做的是指定在市场级别销售的 SMI,并让区域和商店继承 和/或修改这些关系。在上图中,我可以让 Store 1234 从其父美国市场继承 SMI 和关系。我还尝试模拟一个示例,其中美国市场销售 4 件商品,但特定区域 (NY) 仅销售 3 件商品,即纽约地区具有报价关系,但报价已停用(属性)。

这是 Cypher CREATE 语句:

CREATE (:Component {value: "Ketchup"})<-[:made_of]-(n1:BMI {value: "Hamburger", 
version: "default"})-[:made_of]->(oz_Beef_Patty:Component {value: "4oz Beef Patty"}) 
<-[:made_of]-(n13:BMI {value: "Hamburger", version: "New York"})-[:can_add]-> 
(n5:Component {value: "Folded Egg"})<-[:made_of]-(:BMI {value: "Folded Egg"})<- 
[:contains {geoId: "USM"}]-(n15:SMI {value: "Folded Egg"}), (n17:SMI {value: 
"Hamburger"})-[:contains {geoId: 1234}]->(n23:BMI {value: "Hamburger", version: 
"Store 1234"})<-[:contains {geoId: 1234}]-(Hamburger_Extra_Value_Meal:SMI {value: 
"Hamburger Extra Value Meal"})-[:contains {geoId: "NYR"}]->(n13)-[:can_add]-> 
(American_Cheese:Component {value: "American Cheese"})<-[:can_add]-(n1)-[:can_add]-> 
(n5)<-[:can_add]-(n23)-[:made_of]->(Onions:Component {value: "Onions"}), 
(Salt:Component {value: "Salt"})<-[:made_of]-(n1)-[:made_of]->(Onions)<-[:made_of]- 
(n13)-[:made_of]->(Salt)<-[:made_of]-(n23)-[:made_of]->(Mustard:Component {value: 
"Mustard"}), (Pickle:Component {value: "Pickle"})<-[:made_of]-(n1)-[:made_of]-> 
(Mustard)<-[:made_of]-(n13)-[:made_of]->(Pickle), (Roma_Tomato:Component {value: 
"Roma Tomato - 2 Slices"})<-[:can_add]-(n1)-[:made_of]->(Regular_Bun:Component 
{value: "Regular Bun"})<-[:made_of]-(n13)-[:can_add]->(Roma_Tomato)<-[:can_add]- 
(n23)-[:can_add]->(American_Cheese), (New_York_Region:Geo {value: "New York Region", 
level: "Region", id: "NYR"})-[:offers {status: "inactivated"}]->(n15)<-[:offers 
{status: "activated"}]-(US_Market:Geo {value: "US Market", level: "Market", id: 
"USM"})<-[:inherits_from]-(New_York_Region)<-[:inherits_from]-(:Geo {value: "Store 
3456", level: "Store", id: 3456}), (n2:BMI {value: "M French Fry"})<-[:contains 
{geoId: "USM"}]-(Hamburger_Extra_Value_Meal)<-[:offers {status: "activated"}]- 
(US_Market)-[:offers {status: "activated"}]->(n17)-[:contains {geoId: "USM"}]->(n1), 
(:Geo {value: "Store 1234", level: "Store", id: 1234})-[:inherits_from]->(:Geo 
{value: "Chicago Region", level: "Region", id: "CHR"})-[:inherits_from]-> 
(US_Market)-[:offers {status: "activated"}]->(:SMI {value: "M French Fry"})- 
[:contains {geoId: "USM"}]->(n2), (Hamburger_Extra_Value_Meal)-[:contains {geoId: 
"USM"}]->(n1), (n17)-[:contains {geoId: "NYR"}]->(n13), (Regular_Bun)<-[:made_of]- 
(n23)-[:made_of]->(oz_Beef_Patty)

当我执行以下查询时...

MATCH (geo:Geo)-[:inherits_from*0..]->(geos:Geo)
WHERE geo.value = "Store 1234"
WITH geos
OPTIONAL MATCH (geos)-[o:offers]->(smis)-[c:contains]->(bmis)
WHERE c.geoId in [(g1:Geo)-[:inherits_from*0..]->(gs:Geo) WHERE g1.value = "Store 1234" | gs.id]
return geos,smis,bmis

我得到了我期望的产品,即在美国市场级别指定的产品。相反,如果我指定 Store 3456,则节点 Folded Egg 将显示两个地理区域的关系。理想情况下,我希望该地区的关系在结果输出中“取消”美国市场与折叠蛋的关系。

结果:

有谁知道我是如何实现这种关系“分层”或“叠加”的行为?或者也许是另一种建模我的对象以更好地实现上述功能的方式?我不想在区域级别重复美国市场级别已经存在的关系。提前致谢!

在我上面的评论中,我不是试图在模型中创建关系,只是删除查询结果中已经存在的节点的关系。例如,我尝试了以下查询...

MATCH (geo:Geo) 
WHERE geo.value = "Store 3456"
CALL {
    WITH geo
    OPTIONAL MATCH (geo:Geo)-[o1:offers]->(smis)
    RETURN collect(smis) as totalSMIs, collect(geo) as totalGeos
}
CALL {
    WITH geo, totalSMIs, totalGeos
    OPTIONAL MATCH (geo)-[:inherits_from]->(geos1)-[:offers]->(regionSMIs)
    RETURN apoc.coll.union(apoc.coll.removeAll(collect(regionSMIs), totalSMIs), totalSMIs)  AS totalSMIs2, 
        apoc.coll.union(totalGeos, collect(geos1)) as totalGeos2
}
CALL {
    WITH geo, totalSMIs2, totalGeos2
    OPTIONAL MATCH (geo)-[:inherits_from]->(geos1)-[:inherits_from]->(geos2)-[:offers]->(marketSMIs)
    RETURN apoc.coll.union(apoc.coll.removeAll(collect(marketSMIs), totalSMIs2), totalSMIs2) as totalSMIs3, 
        apoc.coll.union(totalGeos2, collect(geos2)) as totalGeos3
}
WITH totalSMIs3, totalGeos3
UNWIND totalGeos3 AS x
UNWIND totalSMIs3 AS y
MATCH (x)-[:inherits_from*0..]->(geos)-[o:offers]->(y)
WHERE o.status <> "inactivated"
RETURN DISTINCT totalSMIs3, totalGeos3

删除链接在不同层次结构级别的节点,我仍然得到所有错误的节点。我试图用上面做的是删除被覆盖的关系。例如,在数据中,美国市场销售折叠蛋([:OFFERS {status:activated}]),但纽约地区用它自己的关系([:OFFERS {status:inactivated}])覆盖了该选择。当我执行上面的代码时,我仍然看到两个 geos 和 Folded Egg 之间的两个关系。我只想要来自纽约地区的节点和关系,而不是来自美国市场 b/c 纽约地区有它自己的关系。

【问题讨论】:

    标签: graph neo4j cypher


    【解决方案1】:

    是的,您说得对,当您创建数据时,您需要检查是否存在市场级别的现有关系,然后再创建另一个区域级别的关系,即纽约地区与 SMI-Folded 之间的关系鸡蛋。

    也许是另一种对我的对象进行建模以更好地实现上述目标的方法 功能

    以下是执行此操作的查询。 1. 查找 SMI(折叠蛋) 2. 创建一个循环,您将在其中检查美国市场是否有此 SMI 的报价 3. 如果未找到,则在此区域(纽约)与此 SMI 之间创建关系

    MATCH (Folded_Egg:SMI {value: "Folded Egg"})
    MATCH (New_York_Region:Geo {value: "New York Region"})
    WITH Folded_Egg, New_York_Region
    FOREACH (_ in CASE NOT EXISTS((:Geo {value: "US Market"})-[:offers]->(Folded_Egg)) when true then [1] else [] end | 
    CREATE (New_York_Region)-[:offers]->(Folded_Egg) )
    RETURN Folded_Egg, New_York_Region
    

    【讨论】:

    • 感谢您的回复。我实际上是在尝试修改查询中返回的关系,而不是在数据库中创建关系。我需要的关系已经存在,我只是想让 Cypher 返回较低级别的关系,而不是“替换”的较高级别的关系。
    • 我明白了。 Cypher 仍会将该关系从 Region 返回到 SMI,因为它将显示数据库中的任何数据。如何在使用数据的应用程序中处理它是否显示它取决于您。
    【解决方案2】:

    我能够创建一个遍历地理层次结构的查询,并且只使用 UNION 和 WITH 语句添加新节点。以下是声明...

    OPTIONAL MATCH (geo)-[o:offers]->(storeSMIs)-[:contains]->(storeBMIs)-[:defined_as]->(storeVers)
    WHERE storeVers.version = o.version AND geo.value = "Store 3456"
    RETURN storeSMIs as totalSMIs, storeBMIs as totalBMIs, storeVers as totalVers
    UNION
    OPTIONAL MATCH (geo)-[o:offers]->(storeSMIs) WHERE geo.value = "Store 3456"
    WITH collect(storeSMIs) as storeSMIs
    OPTIONAL MATCH (geo)-[:inherits_from*1..1]->()-[o2:offers]->(regionSMIs)-[:contains]->(regionBMIs)-[:defined_as]->(regionVers)   
    WHERE regionVers.version = o2.version AND NOT regionSMIs in storeSMIs
        AND geo.value = "Store 3456"
    RETURN regionSMIs as totalSMIs, regionBMIs as totalBMIs, regionVers as totalVers
    UNION
    OPTIONAL MATCH (geo)-[o:offers]->(storeSMIs) WHERE geo.value = "Store 3456"
    WITH collect(storeSMIs) as storeSMIs
    OPTIONAL MATCH (geo)-[:inherits_from*1..1]->()-[o2:offers]->(regionSMIs) WHERE geo.value = "Store 3456"
    WITH storeSMIs, collect(regionSMIs) AS regionSMIs
    OPTIONAL MATCH (geo)-[:inherits_from*2..2]->()-[o3:offers]->(mktSMIs)-[:contains]->(mktBMIs)-[:defined_as]->(mktVers)   
    WHERE mktVers.version = o3.version AND NOT mktSMIs IN storeSMIs
        AND NOT mktSMIs IN regionSMIs AND geo.value = "Store 3456"
    RETURN mktSMIs as totalSMIs, mktBMIs as totalBMIs, mktVers as totalVers
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多