Neo4j:MERGE创建重复的节点

时间:2014-09-25 19:33:44

标签: merge neo4j cypher

我的数据库模型包含用户和MAC地址。用户可以拥有多个MAC地址,但MAC只能属于一个用户。如果某个用户设置了他的MAC并且MAC已经链接到另一个用户,则删除现有关系并在新所有者和该MAC之间创建新关系。换句话说,MAC在用户之间移动。

这是我用于分配MAC地址的Cypher查询的特定实例:

MATCH (new:User { Id: 2 })
MERGE (mac:MacAddress { Value: "D857EFEF1CF6" })
WITH new, mac
OPTIONAL MATCH ()-[oldr:MAC_ADDRESS]->(mac)
DELETE oldr
MERGE (new)-[:MAC_ADDRESS]->(mac)

查询在我的测试中运行正常,但在生产中,由于某些奇怪的原因,有时会创建重复的MacAddress节点(以及用户与每个节点之间的新关系) 。也就是说,特定用户可以拥有多个具有相同MacAddress的{​​{1}}个节点。

我可以说它们是不同的节点,因为它们有不同的节点ID。我也确定Value是完全相同的,因为我可以对它们进行Value,结果是一个带有一个元素的集合。上面的查询是代码中唯一一个创建collect(distinct mac.Value)个节点的查询。

我正在使用Neo4j 2.1.2。这是怎么回事?

谢谢, 扬

2 个答案:

答案 0 :(得分:7)

您确定这是您正在运行的所有查询吗? MERGE有一个非常常见的陷阱,它会合并您提供的所有内容。所以这就是人们的期望:

neo4j-sh (?)$ MERGE (mac:MacAddress { Value: "D857EFEF1CF6" });
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 1
Properties set: 1
Labels added: 1
1650 ms
neo4j-sh (?)$ MERGE (mac:MacAddress { Value: "D857EFEF1CF6" });
+--------------------------------------------+
| No data returned, and nothing was changed. |
+--------------------------------------------+
17 ms
neo4j-sh (?)$ match (mac:MacAddress { Value: "D857EFEF1CF6" }) return count(mac);
+------------+
| count(mac) |
+------------+
| 1          |
+------------+
1 row
200 ms

到目前为止,这么好。这就是我们的期望。现在看这个:

neo4j-sh (?)$ MERGE (mac:MacAddress { Value: "D857EFEF1CF6" })-[r:foo]->(b:SomeNode {label: "Foo!"});
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 2
Relationships created: 1
Properties set: 2
Labels added: 2
178 ms
neo4j-sh (?)$ match (mac:MacAddress { Value: "D857EFEF1CF6" }) return count(mac);                    
+------------+
| count(mac) |
+------------+
| 2          |
+------------+
1 row
2 ms

等等,WTF发生在这里?我们再次只指定了相同的MAC地址,为什么要创建副本?

documentation on MERGE指定“MERGE不会部分使用现有模式 - 它是全部或全部。如果需要部分匹配,可以通过将模式拆分为多个MERGE子句来实现”。因此,当我们运行此路径MERGE时,整个路径尚不存在,它会在其中创建所有内容,包括重复的mac地址节点。

MERGE创建的重复节点经常出现问题,100次中有99次,这就是正在发生的事情。

答案 1 :(得分:6)

这是我从Neo4j的支持中得到的回应(强调我的):

  

我已经从我们的团队得到了一些反馈,目前已经知道这可以在没有约束的情况下发生。 MERGE实际上是MATCH或CREATE - 这两个步骤在事务中独立运行。鉴于并发执行和“读取已提交”隔离级别,两者之间存在竞争条件。

     

团队已就如何在并发性方面提供更高的保证做了一些讨论,并确实将其作为要考虑的功能请求。

     

与此同时,他们向我保证使用约束将提供您正在寻找的唯一性