Neo4j:非中介节点

时间:2014-12-12 15:16:28

标签: transactions neo4j

我在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

before

手术后,我应该有以下图表:

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

after

(边缘方向是任意的,这实际上是一个无向图。)

3 个答案:

答案 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();