neo4j: 将具有相同属性的多个节点替换为一个节点

8
假设我在neo4j中有一个属性为“name”的节点。现在我想通过识别所有具有相同名称的节点来强制实施对给定名称的节点最多只有一个的限制。 更确切地说,如果有三个名称为“dog”的节点,则我希望它们被替换为只有一个名称为“dog”的节点,该节点满足以下条件:
  1. 收集原三个节点的所有属性。
  2. 具有原三个节点附加的所有弧。
背景是:在我的图表中,通常存在几个具有相同名称的节点,应将它们视为“相等”(尽管某些节点具有比其他节点更丰富的属性信息)。在WHERE子句中放置a.name = b.name非常缓慢。
编辑:我忘记提到我的Neo4j目前是2.3.7版本(我无法更新它)。
第二次编辑:节点和可能的弧的标签列表已知。已知节点的类型。
第三次编辑:我希望从Java调用上述“节点折叠”过程,因此Cypher查询和过程代码混合也是一种有用的解决方案。

这些节点的标签已知吗?它们所有的标签都一样吗?那么这些节点的关系类型呢? - stdob--
如果Node1(名称=A)和Node2(名称=A)具有相同的属性但值不同,应该发生什么? - K.E.
@K.E. 在我这种情况下并不重要。可以选择删除其中一个值,或者为给定的“属性”定义“属性2”。最重要的是收集所有的弧线,也就是说新节点应该具有与替换节点相同标签的所有入弧和出弧。我提出请求的主要原因是我有很多弧线A -> B1,B2 -> C,其中B1和B2实际上是同一个节点,并且关系A -> B -> C是我想找到的关系。 - J Fabian Meier
2个回答

5

我认为你需要的是节点的同义词。

1)遍历所有节点并创建节点的同义词:

MATCH (N)
WITH N
  MERGE (S:Synonym {name: N.name})
  MERGE (S)<-[:hasSynonym]-(N)
RETURN count(S);

2) 删除仅有一个节点的同义词:

MATCH (S:Synonym)
WITH S
MATCH (S)<-[:hasSynonym]-(N)
WITH S, count(N) as count
WITH S WHERE count = 1
DETACH DELETE S;

3)使用apoc,翻译剩余同义词的传输属性和关系:

MATCH (S:Synonym)
WITH S
MATCH (S)<-[:hasSynonym]-(N)
WITH [S] + collect(N) as nodesForMerge
CALL apoc.refactor.mergeNodes( nodesForMerge );

4) 移除Synonym标签:

MATCH (S:Synonym)<-[:hasSynonym]-(N)
CALL apoc.create.removeLabels( [S], ['Synonym'] );

非常感谢您详细的回答。不幸的是,jqassistant使用的是Neo4j 2.3.3版本,而apoc似乎需要3.0.0版本。 - J Fabian Meier
@JFMeier请在这些限制下更正原始问题。 - stdob--

5

我已经使用以下模式创建了一个测试用例:

CREATE (n1:TestX {name:'A', val1:1})
CREATE (n2:TestX {name:'B', val2:2})
CREATE (n3:TestX {name:'B', val3:3})
CREATE (n4:TestX {name:'B', val4:4})
CREATE (n5:TestX {name:'C', val5:5})

MATCH (n6:TestX {name:'A', val1:1}) MATCH (m7:TestX {name:'B', val2:2}) CREATE (n6)-[:TEST]->(m7)
MATCH (n8:TestX {name:'C', val5:5}) MATCH (m10:TestX {name:'B', val3:3}) CREATE (n8)<-[:TEST]-(m10)

以下输出结果是什么:

enter image description here

节点B实际上是相同的节点。这是我的解决方案:

//copy all properties
MATCH (n:TestX), (m:TestX) WHERE n.name = m.name AND ID(n)<ID(m) WITH n, m SET n += m;

//copy all outgoing relations
MATCH (n:TestX), (m:TestX)-[r:TEST]->(endnode) WHERE n.name = m.name AND ID(n)<ID(m) WITH n, collect(endnode) as endnodes
FOREACH (x in endnodes | CREATE (n)-[:TEST]->(x));

//copy all incoming relations
MATCH (n:TestX), (m:TestX)<-[r:TEST]-(endnode) WHERE n.name = m.name AND ID(n)<ID(m) WITH n, collect(endnode) as endnodes
FOREACH (x in endnodes | CREATE (n)<-[:TEST]-(x));

//delete duplicates
MATCH (n:TestX), (m:TestX) WHERE n.name = m.name AND ID(n)<ID(m) detach delete m;

生成的输出如下所示:

enter image description here

必须指出,您需要了解各种关系的类型。
所有属性都从具有“更高”ID的节点复制到具有“较低”ID的节点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接