【问题标题】:Why multiple nodes are created in Neo4j by CREATE or MERGE query为什么在 Neo4j 中通过 CREATE 或 MERGE 查询创建多个节点
【发布时间】:2018-05-19 18:59:17
【问题描述】:

我正在使用CypherNeo4j 中创建一些数据。这是一个非常简单的产品模型,具有以下元素

  1. 产品(例如手机)
  2. 功能(例如快速充电)
  3. 相关产品(例如钢化玻璃)
  4. 奥特莱斯(例如本地商店,相关产品通过奥特莱斯销售)

我写了一些查询来插入数据。它试图做的事情

  • 创建产品
  • 创建功能集
  • 将产品与功能 [:HAS_FEATURES] 关联
  • 创建网点 x3
  • 创建相关产品1
  • 将产品链接到相关产品 [:HAS_RP],并将相关产品链接到所有网点 [:SOLD_THROUGH]
  • 创建相关产品2
  • 将其链接到上述产品和网点

下面是实际查询

//Product
CREATE (p:Product {name: 'Cool Mobile YX Plus',
  key: 'MOB0001',
  version: 'X.1'
}),

//Features
(f:Features {hasQuickCharge: true,
  isAvailable: true,
  hasVolte: false
})

MERGE (p) -[:HAS_FEATURES]-> (f)

//Outlets (:Product level lookup)
CREATE (o1:Outlet {productType: 'New', seller: 'National_Shops', prId: 'MOB0001'})
CREATE (o2:Outlet {productType: 'New', seller: 'Local_Shops', prId: 'MOB0001'})
CREATE (o3:Outlet {productType: 'New', seller: 'Online_Shops', prId: 'MOB0001'})

//Related products
CREATE (rps1:RPS {rpId: 'TGS1108',
  rpName: 'YX Plus Tampered Glass',
  price: 180.99
})
WITH rps1
MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'})
MATCH (pr1:Product {key: 'MOB0001'})
MERGE (pr1) -[:HAS_RP {typeName: 'Child'}]-> (rps1)
MERGE (rps1) -[:SOLD_THROUGH]-> (ol1)

CREATE (rps2:RPS {rpId: 'CVR0204',
  rpName: 'YX Plus back cover',
  price: 299.00
})
WITH rps2
MATCH (ol2:Outlet {productType: 'New', prId: 'MOB0001'})
MATCH (pr2:Product {key: 'MOB0001'})
MERGE (pr2) -[:HAS_RP {typeName: 'ChargeFor'}]-> (rps2)
MERGE (rps2) -[:SOLD_THROUGH]-> (ol2)

现在的问题是,第二个相关产品被创建了 3 次,而它预计只会被创建一次,就像第一个相关产品一样。

谁能帮我理解我做错了什么?此外,以更好的方式编写查询的任何帮助都会很棒。

【问题讨论】:

    标签: graph neo4j cypher graph-databases cypher-3.1


    【解决方案1】:

    问题在这里:

    MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'})

    您在符合 MATCH 标准的 3 个节点之前创建:

    CREATE (o1:Outlet {productType: 'New', seller: 'National_Shops', prId: 'MOB0001'}) CREATE (o2:Outlet {productType: 'New', seller: 'Local_Shops', prId: 'MOB0001'}) CREATE (o3:Outlet {productType: 'New', seller: 'Online_Shops', prId: 'MOB0001'})

    所以,MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'}) 将返回 3 行,并且对于每一行,它将执行查询的下一部分,此部分的 3 次:

    MATCH (pr2:Product {key: 'MOB0001'})
    MERGE (pr2) -[:HAS_RP {typeName: 'ChargeFor'}]-> (rps2)
    MERGE (rps2) -[:SOLD_THROUGH]-> (ol2)
    

    【讨论】:

    • 作为补充,这里有一篇关于resetting cardinality 的知识库文章,在查询的不相关部分之间,如本例所示。
    • 您好 Christophe,感谢您的回答。我的困惑是,为什么这只发生在第二个查询(YX Plus 封底),而不是第一个查询(YX Plus Tampered Glass)?例如,如果我删除第二个,第一个就可以了!
    • @InverseFalcon 啊,现在我明白了。感谢您的链接。因此,造成问题的不是 MERGE 部分(如链接中所述,虽然很重但有效),但 CREATE(YX Plus 后盖)被触发了 3 次!
    【解决方案2】:

    只是为 @Christophe 和 @InverseFalcon 已经回答/评论的内容编写扩展。如resetting query cardinality 中所述,此问题是由多次执行CREATE 引起的。

    查询按行执行。因此,当 MATCH 后跟 CREATE 时,根据匹配结果,CREATE 语句可能会被执行多次并创建数据的多个副本(除非存在唯一/节点键约束),这原本是为了只能创建一次。

    MERGE 可以帮助解决这些问题,因为它不会创建多个副本,但 MERGE 仍会执行多次。

    这可以通过使用WITH DISTINCT“重置查询基数”来处理。下面显示了解决问题的更新查询,该图显示了新结果。

    //Related products
    CREATE (rps1:RPS {rpId: 'TGS1108',
      rpName: 'YX Plus Tampered Glass',
      price: 180.99
    })
    WITH rps1
    MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'}) //3 match
    MATCH (pr1:Product {key: 'MOB0001'})
    MERGE (pr1) -[:HAS_RP {typeName: 'Child'}]-> (rps1)
    MERGE (rps1) -[:SOLD_THROUGH]-> (ol1)
    
    //next part of query will execute 3 times
    
    //reset cardinality back to 1 with WITH DISTINCT
    WITH DISTINCT 1 AS ResetCardinality
    CREATE (rps2:RPS {rpId: 'CVR0204',
      rpName: 'YX Plus back cover',
      price: 299.00
    }) //now CREATE & following executes only once
    WITH rps2
    MATCH (ol2:Outlet {productType: 'New', prId: 'MOB0001'})
    MATCH (pr2:Product {key: 'MOB0001'})
    MERGE (pr2) -[:HAS_RP {typeName: 'ChargeFor'}]-> (rps2)
    MERGE (rps2) -[:SOLD_THROUGH]-> (ol2)
    

    由于我是新手,如果有人可以展示如何通过更好的书面查询更好地处理整个情况,那将有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      • 2014-01-04
      • 2015-09-04
      • 2014-08-27
      • 1970-01-01
      相关资源
      最近更新 更多