Transactions Neo4j:去中介节点

Transactions Neo4j:去中介节点,transactions,neo4j,Transactions,Neo4j,我在Neo4J(Community version 2.1.6)中有一个图,其中有一个特定类型的节点,TypeX,我希望删除该节点的所有实例,用保留现有连接的边替换其位置。从概念上讲,这类似于表示多条边的TypeX,并将其替换为连接到该多条边的节点的完全连接子图 我尝试使用以下密码查询,但遇到事务问题: MATCH (c)-[e1]-(a:TypeX)-[e2]-(b) CREATE UNIQUE c-[:CONNECTED_TO]-b DELETE a, e1, e2; +----------

我在Neo4J(Community version 2.1.6)中有一个图,其中有一个特定类型的节点,
TypeX
,我希望删除该节点的所有实例,用保留现有连接的边替换其位置。从概念上讲,这类似于表示多条边的
TypeX
,并将其替换为连接到该多条边的节点的完全连接子图

我尝试使用以下密码查询,但遇到事务问题:

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}),(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我认为你基本上是对的,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;

这里有一个我已经开始工作的解决方案,使用JavaAPI一次删除一个节点。这显然比密码查询要详细得多

    // '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();
/“db”是此处的“GraphDatabaseService”对象
事务tx=db.beginTx();
String type=“TypeX”;
String relType=“连接到”;
标签toEliminate=DynamicLabel.Label(类型);
List todelite=new ArrayList();
for(节点n:GlobalGraphOperations.at(db).getAllNodesWithLabel(toEliminate))
添加((字符串)n.getProperty(“id”);
String query=“匹配(c)-[e1]-(a:”+类型+
“{id:{id}}-[e2]-(b)合并c-[:“+relType+”]-b删除a、e1、e2”;
ExecutionEngine=新ExecutionEngine(db);
for(字符串nodeId:toDelete){
execute(query,MapUtil.map(“id”,nodeId));
}
成功();
tx.close();

我不确定我是否完全明白这个问题,但这里有一个答案。我认为您希望删除标记为
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约束,然后验证所有中间节点是否为正确的“type”。如果在子集合上有匹配机制,我们可以放弃
node=c或node=b
组件

我发现这个稍微复杂一点的版本稍微快一点,因为它删除了多次访问同一节点的路径(初始的
where
子句)

如果关系有一个类型(不同节点之间的类型不同),那么这一切都会简单一些,不是吗

如果可以,可以提高速度

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

当然,如果可以的话,这三种方法都会有好处。

可以
c
b
成为
TypeX
节点,或者它们总是其他标签/无标签的吗?哦,我想我明白了问题所在。因为它一次只能工作一条路径,如果一个TypeX节点将一个节点连接到另两个节点,那么没有des,则无法删除该TypeX节点,因为它仍然连接到它不工作的节点on@BrianUnderwood-它们也可以是
TypeX
节点,我认为这是问题的症结所在。我编辑了一些示例数据,得到了预期的结果。您还可以将create unique移到最后。删除之后。很遗憾这两个查询似乎都不起作用。第一个查询确实运行,但它中断了连接-结果应具有与原始查询相同数量的连接组件。第二个查询失败,并出现与原始查询相同的事务问题。如果我可以首先枚举从非
TypeX
节点到任何number
1..
TypeX
节点,在不同的非
TypeX
节点结束-然后我可以向所有这些节点对添加唯一的边,然后我可以自由删除所有
TypeX
节点及其边。我显示的第二个代码块的第一个查询是否保留连接?如果是,您可能需要用我的编辑再次尝试第二个查询。我想如果
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 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)