删除 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 MATCHON create at全部。只需直接执行 2 个不同的 SET 操作:SET p.name = line.name, p.residence = line.residence 啊啊啊……是的,这是有道理的。 ON CREATE / ON MATCH 基本上只是意味着SET。谢谢!! 但是等等。我使用ON MATCHON 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 图中多余的双向关系的主要内容,如果未能解决你的问题,请参考以下文章

UML

如何在 Neo4J 中处理队列?

hibernate多对多双向关系映射的级联配置

如何通过级联级联@ManyToOne 双向关系?

在JPA双向@OnetoMany关系中,当我更新父实体时,子实体在数据库中被删除

如何统计图中常见的双向连接数