为什么MERGE有时会创建重复的关系?

时间:2017-02-04 02:21:08

标签: neo4j cypher

我的上一个问题因重复Confused about MERGE sometimes creating duplicate relationship而被关闭,但是我无法找到解决方案,这会处理重复的关系,而不是重复的节点。

当用户VISITED其他用户的个人资料

时,我有一个查询
    MATCH (you:User {user_id: { myId }}), (youVisited:User {user_id: { id }})
    MERGE (you)-[yvr:VISITED]->(youVisited)
    SET yvr.seen = false, yvr.created_at = timestamp()
    RETURN yvr.created_at as visited_at

我注意到在极少数情况下会发生重复的[:VISITED]关系。对于(1057)-[:VISITED]->(630),两者都具有相同的属性,并且实际上只应该是一个[:VISITED]无论什么(下次用户访问时,它应该只是MERGE {{1}并更新相同用户节点之间的[:VISITED]

[:VISITED {created_at: ..., seen: false}]

enter image description here

我认为{ created_at: 1485800172734, seen: false } 要防止这种情况发生?显然不是,为什么会发生这种情况,我怎样才能确保不会发生这种情况呢?

我查了一些其他的东西,但我不确定这些信息是否可靠或是最新的。例如:http://neo4j.com/docs/developer-manual/current/cypher/clauses/create-unique/,我应该使用MERGE吗?我认为CREATE UNIQUE几乎是一个更好的替代品。

2 个答案:

答案 0 :(得分:2)

我同意在某些情况下,MERGECREATE UNIQUE可用于同一目的。但是,MERGE不会取代CREATE UNIQUE

例如,MERGE允许多个匹配,并且其模式必须完全匹配图形才被视为匹配 - 它将简单地复制部分匹配;另一方面,CREATE UNIQUE会在多个匹配项上出错,并允许部分匹配 - 它会尝试重新使用图表的现有部分并添加缺少的部分。

正如docs中所提到的,关系的唯一性似乎也存在差异,即您所遇到的问题:

  

MERGE可能是您想要使用的而不是CREATE UNIQUE。但请注意,MERGE并不能保证关系的独特性。

我会让Neo4j的开发人员准确解释这些保证是什么。我只能说,在你的特定情况下,CREATE UNIQUE似乎比MERGE更合适:如果你的意图是只允许一个用户与另一个用户之间的单一VISITED关系 - 他的上次访问 - 多个VISITED关系违反了您的数据模型,然后一定要使用CREATE UNIQUE来记录此意图,并在数据库级别强制执行同一时间。

在这种情况下,可以说VISITED关系也没有特别好的命名,因为它意味着可能有更多:每次用户访问另一个用户的个人资料时都有一个。

答案 1 :(得分:1)

正如我的评论中所提到的,在Neo4j切换到COST规划师时,有一个locking bug MERGE。

据我所知,它的工作原理如下:

由于该错误,双重检查锁定没有发生,因此在MERGE确定关系不存在之后,它会锁定节点以准备创建关系,但是那里有“sa”。在存在检查关系和锁定之间的竞争条件,因此并发MERGE或CREATE可能在获取锁之前创建了关系,从而导致创建重复关系。

修复将确保MERGE在获取锁之后再次检查是否存在关系。这应该恢复MERGE的并发保证。

截至2017年2月2日,此修复程序尚未发布到当前的Neo4j版本中。

与此同时,您可以在MERGE之前显式锁定相关节点,以防止竞争条件。

您可以通过在相关节点上设置/删除不存在的值来执行此操作,或使用APOC locking procedures