我在Neo4J(社区版本2.1.6)中有一个图表,它有一个特定类型的节点TypeX
,我想删除它的所有实例,用保留现有连接的边缘替换它的位置。从概念上讲,这类似于TypeX
表示多边缘,并将其替换为连接到该多边缘的节点的完全连接子图。
我尝试使用以下Cypher查询,但遇到了交易问题:
MATCH (c)-[e1]-(a:TypeX)-[e2]-(b)
CREATE UNIQUE c-[:CONNECTED_TO]-b
DELETE a, e1, e2;
+-------------------+
| No data returned. |
+-------------------+
Relationships created: 18276
Nodes deleted: 7677
Relationships deleted: 13546
1571 ms
TransactionFailureException: Unable to commit transaction
我想这是因为一些TypeX
节点可能连接到其他TypeX
节点,并且两个这样的相邻节点上的操作相互冲突。
有没有办法在"贪心"中运行这样的查询?时尚,以便逐个挑选TypeX
节点并消除?我对Neo4J来说还是比较新的,所以可能会有一些我可以忽视的东西。
[更新]:以下是一些示例数据:
CREATE (a:Foo {id:"a"}), (b:TypeX {id:"b"}), (c:Bar {id:"c"}),
(d:TypeX {id:"d"}), (e:TypeX {id:"e"}),
(f:Foo {id:"f"}), (g:Foo {id:"g"}),
a-[:Z]->b-[:Z]->c<-[:Z]-d<-[:Z]-e,
f-[:Z]->e<-[:Z]-g<-[:Z]-f
手术后,我应该有以下图表:
CREATE (a:Foo {id:"a"}), (c:Bar {id:"c"}),
(f:Foo {id:"f"}), (g:Foo {id:"g"}),
a-[:Z]->c,
f-[:Z]->c<-[:Z]-g
(边缘方向是任意的,这实际上是一个无向图。)
答案 0 :(得分:1)
我认为您在完全删除之前删除的TypeX节点基本上是正确的。
这可能有用,但我对此表示怀疑:
MATCH (c)-[e1]-(a:TypeX)-[e2]-(b)
CREATE UNIQUE c-[:CONNECTED_TO]-b
WITH a
MATCH (c)-[e1]-(a)-[e2]-(b)
DELETE a, e1, e2;
否则我认为你想做两个问题:
MATCH (c)-[e1]-(a:TypeX)-[e2]-(b)
CREATE UNIQUE c-[:CONNECTED_TO]-b;
MATCH (c)-[e1]-(a:TypeX)
WHERE NOT(type(e1) = 'CONNECTED_TO') AND NOT(c:TypeX)
DELETE a, e1;
答案 1 :(得分:1)
我不确定我是否完全接受了这个问题,但这是一个答案。我相信您要删除标记为TypeX
的节点的所有实例,这意味着您需要从找到它们开始。
当前解决方案仅在节点出现在某些模式中间时才匹配节点。这是要求,还是TypeX
节点可以存在于图的边缘?
我修改了您的路径匹配,以查找多个TypeX
节点相关的节点(请注意e1
匹配中的*)。此外,我们对加入我们要删除的节点不感兴趣,因此请在WHERE
子句中将其排除。
MATCH p=(c)-[e1*]-(a:TypeX)-[e2]-(b)
WHERE NOT (b:TypeX) AND NOT (c:TypeX)
我赞成MERGE
来创建新关系:
MERGE c-[:CONNECTED_TO]-b
然后删除原始路径中的所有关系:
FOREACH (rel IN rels(p)|
DELETE rel)
最后删除原始匹配的所有实例:
WITH a
DELETE a
我相信这个或它的一个小变体将解决你的问题。完成:
MATCH p=(c)-[e1*]-(a:TypeX)-[e2]-(b)
WHERE NOT (b:TypeX) AND NOT (c:TypeX)
MERGE c-[:CONNECTED_TO]-b
FOREACH (rel IN rels(p)|
DELETE rel)
WITH a
DELETE a
编辑 - 修复不充分的答案
这突然变得非常复杂,我相信它不应该是,我希望有人会介入减少这种方法:
MATCH p=(c)-[e1*]-(a:TypeX)-[e2]-(b)
WHERE NOT (b:TypeX) AND NOT (c:TypeX) AND ALL (node IN NODES(p)
WHERE node = c OR node = b OR node:TypeX)
MERGE c-[:CONNECTED_TO]-b
FOREACH (rel IN rels(p)|
DELETE rel)
WITH a
DELETE a
现在你有一个WHERE
子句,它在路径的两端强制执行not of type约束,然后验证所有中间节点是否都是正确的&#39;类型&#39;。如果有一个匹配子集合的机制,我们可以放弃node =c OR node = b
组件。
我发现这个稍微复杂一点的版本稍微快一些,因为它删除了多次访问同一节点的路径(最初的WHERE
子句)。
MATCH p=(c)-[e1*]-(a:TypeX)-[e2]-(b)
WHERE ALL (n IN NODES(p)
WHERE 1=LENGTH(FILTER(m IN NODES(p)
WHERE m=n)))
WITH p, a, c, b
WHERE NOT (b:TypeX) AND NOT (c:TypeX) AND ALL (node IN NODES(p)
WHERE node = c OR node = b OR node:TypeX)
MERGE c-[:CONNECTED_TO]-b
FOREACH (rel IN rels(p)|
DELETE rel)
WITH a
DELETE a
如果关系有一个类型(并且不同节点之间的类型不一样),这一切都会更简单一些,但事实并非如此!?
如果可以的话,提高速度
在b和c上使用标签(索引引擎的帮助,加上删除一些(因为没有节点标记为Foo和TypeX)where子句:
MATCH p=(c:Foo)-[e1*]-(a:TypeX)-[e2]-(b:Foo)
WHERE ALL (node IN NODES(p)
WHERE node = c OR node = b OR node:TypeX)
限制e1中可能的跳数,这将减少匹配次数,从而减少必须在过滤器中完成的工作量:
MATCH p=(c)-[e1*1..2]-(a:TypeX)-[e2]-(b)
WHERE NOT (b:TypeX) AND NOT (c:TypeX) AND ALL (node IN NODES(p)
WHERE node = c OR node = b OR node:TypeX)
如果关系有不同的类型,您可以使用MATCH
中的类型来提高效率:
MATCH p=(c)-[e1:OLD_REL_FOO_TO_X*]-(a:TypeX)-[e2::OLD_REL_FOO_TO_X]-(b)
WHERE NOT (b:TypeX) AND NOT (c:TypeX) AND ALL (node IN NODES(p)
WHERE node = c OR node = b OR node:TypeX)
根据您的确切数据,会有更多内容。如果可以,显然要做所有这三项,但每项都会产生效益。
答案 2 :(得分:0)
这是我已经开始使用的一个解决方案,使用Java API一次删除一个节点。它显然比Cypher查询更冗长!
// 'db' is a 'GraphDatabaseService' object here
Transaction tx = db.beginTx();
String type = "TypeX";
String relType = "CONNECTS_TO";
Label toEliminate = DynamicLabel.label(type);
List<String> toDelete = new ArrayList<String>();
for (Node n : GlobalGraphOperations.at(db).getAllNodesWithLabel(toEliminate))
toDelete.add((String) n.getProperty("id"));
String query = "MATCH (c)-[e1]-(a:" + type +
" {id:{id}})-[e2]-(b) MERGE c-[:" + relType + "]-b DELETE a, e1, e2";
ExecutionEngine engine = new ExecutionEngine(db);
for (String nodeId : toDelete) {
engine.execute(query, MapUtil.map("id", nodeId));
}
tx.success();
tx.close();