删除 Neo4j 图中多余的双向关系
Posted
技术标签:
【中文标题】删除 Neo4j 图中多余的双向关系【英文标题】:Remove redundant two way relationships in a Neo4j graph 【发布时间】:2016-09-10 22:44:40 【问题描述】:我有一个国际象棋锦标赛的简单模型。它有5名玩家互相比赛。图表如下所示:
图表总体上很好,但进一步检查后,您可以看到两组 Guy1 与 Guy2, 和 Guy4 vs Guy5 每个都有冗余关系。
问题显然出在数据中,其中每个匹配项都有一个无关的补充行(因此从某种意义上说,这是底层 csv 中的数据质量问题):
我可以手动清理这些行,但真正的数据集有数百万行。所以我想知道如何使用 CQL 以两种方式中的任何一种来删除这些关系:
1) 一开始就不要阅读额外的关系
2) 继续创建额外的关系,但稍后将其删除。
提前感谢您对此的任何建议。
我使用的代码是这样的:
/ Here, we load and create nodes
LOAD CSV WITH HEADERS FROM
'file:///.../chess_nodes.csv' AS line
WITH line
MERGE (p:Player
player_id: line.player_id
)
ON CREATE SET p.name = line.name
ON MATCH SET p.name = line.name
ON CREATE SET p.residence = line.residence
ON MATCH SET p.residence = line.residence
// Here create the edges
LOAD CSV WITH HEADERS FROM
'file:///.../chess_edges.csv' AS line
WITH line
MATCH (p1:Player player_id: line.player1_id)
WITH p1, line
OPTIONAL MATCH (p2:Player player_id: line.player2_id)
WITH p1, p2, line
MERGE (p1)-[:VERSUS]->(p2)
【问题讨论】:
这与您的问题没有直接关系,但这些查询有很多无关的子句。 1.ON CREATE blah
/ON MATCH blah
对可以只替换为单个blah
。 2. WITH
子句没有任何用途,可以删除。
对于#1,首选语法是什么?
由于要执行完全相同的SET
操作,因此无论MERGE
是创建新节点还是匹配现有节点,都不应使用ON MATCH
和ON create
at全部。只需直接执行 2 个不同的 SET
操作:SET p.name = line.name, p.residence = line.residence
。
啊啊啊……是的,这是有道理的。 ON CREATE / ON MATCH
基本上只是意味着SET
。谢谢!!
但是等等。我使用ON MATCH
和ON CREATE
作为解决方案,因为我的数据有一些缺失值,而MERGE
的缺失值很糟糕。
【参考方案1】:
很明显,您不需要这种额外的关系,因为它不会为图表添加任何价值或权重。
尽管在文档中,但很少有人知道。
MERGE
可用于undirected
关系,neo4j 将为您选择一个方向(因为关系必须在图中指示)。
文档参考:http://neo4j.com/docs/stable/query-merge.html#merge-merge-on-an-undirected-relationship
如果你是第一次运行,下面的语句示例:
MATCH (a:User name:'A'), (b:User name:'B')
MERGE (a)-[:VERSUS]-(b)
它将创建不存在的关系。但是,如果您再次运行它,则不会更改或创建任何内容。
我想这会解决您的问题,因为您不必担心预先清理数据,也不必担心事后运行脚本来清理图表。
【讨论】:
尽管如此,并不是每个玩家最终都会互相玩(例如,如果你看一下图表,你会发现 Guy3 和 Guy5 实际上并没有玩)。这段代码是否会创建不存在的匹配项? 好吧,如果您的 edges.csv 文件中没有代表 Guy3 和 Guy5 之间关系的行,则不会创建 啊,我明白你的意思了。像MATCH (p1:Player player_id: line.player1_id), (p2:Player player_id: line.player2_id) MERGE (p1)-[:VERSUS]-(p2)
这样的东西。我仍然收到我以前见过的警告:This query builds a cartesian product between disconnected patterns.
如果你在 :Player(player_id) 上有索引,不要担心警告【参考方案2】:
我建议像这样创建一个“匹配”节点
(x:Player)-[:MATCH]->(m:Match)<-[:MATCH]-(y:Player)
启用与玩家分开的关于比赛的跟踪详细信息。
如果您需要跟踪与比赛本身不同的球员比赛,那么
(x:Player)-[:HAS_PLAYED]->(pair:HasPlayed)<-[:HAS_PLAYED]-(y:Player)
会成功的。
【讨论】:
我正计划使用边缘来保存有关匹配的信息...您是否建议更改架构?我宁愿保持原样,只删除冗余。 Tim - 虽然拥有一个 Match 节点可能是一个很好的建议(或者至少可以进行有趣的讨论),但这并不能回答删除冗余关系的核心问题。 恕我直言,核心问题不是冗余关系,而是架构的组织方式。 这个问题可以通过多种方式解决,我非常感谢您的时间和投入,因为我提高了对 Neo4j 的理解。我已经从 SO 中学到了很多东西,非常感谢所有输入。【参考方案3】:如果架构必须保持原样并且唯一的要求是删除冗余关系,那么
MATCH (p1:Player)-[r1:VERSUS]->(p2:Player)-[r2:VERSUS]->(p1)
DELETE r2
应该可以解决问题。这将找到所有具有双向 VERSUS 关系的 p1、p2 节点并删除其中一个。
【讨论】:
应该是 MATCH (p1:Player)-[r1:VERSUS]->(p2:Player)-[r2:VERSUS]->(p1) WHERE id(p1) 运行代码删除了两个方向。我应该在尝试之前阅读评论,这似乎可以解决它。但从现在开始,我将避免创建它们。 这应该是 OP 问题中选项 #2 的公认答案。在我的情况下也很好用!【参考方案4】:您需要使用 UNWIND 来解决问题。
MATCH (p1:Player)-[r:VERSUS]-(p2:Player)
WITH p1,p2,collect(r) AS rels
UNWIND tail(rels) as rel
DELETE rel;
前面的代码将使用 match 找到 p1 和 p2 之间的 VERSUS 类型的直接连接(请注意,这不是定向的)。然后将得到关系的集合,最后是这些关系中的最后一个,它被删除。 当然也可以加个检查看看集合的长度是否为2。
【讨论】:
以上是关于删除 Neo4j 图中多余的双向关系的主要内容,如果未能解决你的问题,请参考以下文章