在Cypher中删除所有节点和关系的最佳方法

18

在https://dev59.com/h2Uq5IYBdhLWcg3wNtyB中,他们建议删除整个数据库目录,但我对于需要提供用户清除图形(将状态重置为默认)的远程GUI感兴趣。 - George Birbilis
7个回答

23

正如您所提到的,最简单的方法是停止Neo4j,删除 data/graph.db 文件夹并重新启动它。

通过Cypher删除大型图形将始终较慢,但如果您使用适当的事务大小来防止内存问题(请记住,在提交之前,事务首先在内存中构建),仍然可以完成。通常,50-100k个原子操作是一个好主意。您可以向删除语句添加限制以控制事务大小,并报告已删除多少节点。重复运行此语句,直到返回值为0:

MATCH (n)
OPTIONAL MATCH (n)-[r]-()
WITH n,r LIMIT 50000
DELETE n,r
RETURN count(n) as deletedNodesCount

2
这个问题在Zoomicon的网站上被提出: "在您最后一个查询中,您创建了一个巨大的交叉积。所有节点乘以所有关系。可能更清洁的方法是将其拆分为两个部分,先删除关系,然后再删除节点"。 - NumenorForLife
1
删除文件夹:rm -rf data/graph.db - Stefan Armbruster
1
@jsc123 - 这个问题是指我最初想要使用MATCH (n), ()-[r]-() DELETE n,r的方法,但这种方法并不高效,因为它会产生一个交叉乘积,而且查询优化器似乎无法对其进行优化。在我看来,它应该检查n和r在MATCH之后的使用方式是否无关,从而在内部将其拆分为两个单独的查询,并在一步中执行它们,但也许我要求太多了。 - George Birbilis
1
关于删除数据/ graph.db 子文件夹(它是一个包含扩展名的子文件夹,而不是文件),显然 neo4j 会重新创建它。但是我想您需要先停止 neo4j 服务器,然后再重新启动它。在 Windows 上使用 RMDIR /S/Q 路径来删除目录树 (/S) 而无需进行确认 (/Q)。 - George Birbilis
有人知道如何在使用Java驱动程序创建节点和关系时删除它们吗? - Aqqqq
显示剩余4条评论

13
根据官方文档此处
MATCH (n)
DETACH DELETE n

但它还说:此查询不适用于删除大量数据。 因此最好在使用时添加限制。

match (n)  
with n limit 10000  
DETACH DELETE n;  

由于您提到了DETACH,它在您指向的文档中写道:“您无法删除节点而不同时删除始于或终止于该节点的关系。要么明确删除这些关系,要么使用DETACH DELETE。” - George Birbilis
顺便说一句,如果您使用LIMIT(出于性能原因),猜测您还需要使用RETURN count(n)作为deletedNodesCount,并重复运行它直到返回0,如上面其他回答中所建议的。 - George Birbilis

4

我写了这个小脚本,把它加入了我的NEO/bin文件夹中。

在v3.0.6社区版上进行了测试。

#!/bin/sh
echo Stopping neo4j
./neo4j stop
echo Erasing ALL data
rm -rf ../data/databases/graph.db
./neo4j start
echo Done

当我的LOAD CSV导入出现问题时,我会使用它。

希望能有所帮助。


2

如何通过Cypher清理图形中的所有节点和关系的最佳方法是什么?

截至2022年7月,以下列出了四个选项:

  • 选项1:MATCH(x)DETACH DELETE x
  • 选项2:在事务中调用 {}
  • 选项3:删除数据目录
  • 选项4:在代码中删除

选项1:MATCH(x)DETACH DELETE x - 仅适用于小型数据集

正如您在问题中发布的那样,以下内容很好,但仅适用于节点和关系不太多的情况:

MATCH (x) DETACH DELETE x

如果节点和/或关系的数量足够大,这种方法将无法运行。以下是针对 http://localhost:7474/browser/ 的“无法运行”示例:

没有足够的内存执行当前任务。请尝试在 neo4j 配置中增加 'dbms.memory.heap.max_size'(通常在 'conf/neo4j.conf' 中,如果您使用 Neo4j Desktop,则可以通过用户界面找到),或者如果您正在运行嵌入式安装,则使用 '-Xmx' 命令行标志增加堆大小,然后重新启动数据库。

以下是在 neo4j 控制台输出(或日志中,如果您已启用该功能)中显示的内容:
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "neo4j.Scheduler-1"

选项2:在事务中调用{} - 2022年7月之前不起作用

根据neo4j文档,从版本4.4开始,另一种选择是使用新的CALL {} IN TRANSACTIONS功能:

在4.4及更高版本中,您可以利用CALL {} IN TRANSACTIONS语法[...]以批处理方式删除匹配记录的子集,直到完全删除为止

不幸的是,在我的测试中,这并不起作用。以下是一个仅尝试删除关系的示例:

MATCH ()-[r]-()
CALL { WITH r DELETE r }
IN TRANSACTIONS OF 1000 ROWS

在浏览器中运行会导致以下错误:

使用“CALL { ... } IN TRANSACTIONS”的查询只能在隐式事务中执行,但尝试在显式事务中执行。

在代码中,它产生相同的结果。这里是一个通过Java使用Bolt连接的尝试:
session.executeWrite(tx -> tx.run("MATCH (x) " +
        "CALL { WITH x DETACH DELETE x } " +
        "IN TRANSACTIONS OF 10000 ROWS"));

由此产生了与浏览器显示完全相同的错误:
org.neo4j.driver.exceptions.DatabaseException: A query with 'CALL { ... } IN TRANSACTIONS' can only be executed in an implicit transaction, but tried to execute in an explicit transaction.
    at org.neo4j.driver.internal.util.Futures.blockingGet(Futures.java:111)
    at org.neo4j.driver.internal.InternalTransaction.run(InternalTransaction.java:58)
    at org.neo4j.driver.internal.AbstractQueryRunner.run(AbstractQueryRunner.java:34)

看一下事务文档,它说:“事务可以是显式的或隐式的。”有什么区别?从同一文档中获得以下信息:

显式事务:

  • 由用户打开。
  • 可以按顺序执行多个Cypher查询。
  • 由用户提交或回滚。

隐式事务,有时称为自动提交事务或:auto事务:

  • 会自动打开。
  • 只能执行单个Cypher查询。
  • 当查询成功完成时,将自动提交。
我无法确定如何打开隐式事务(因此,无法使用'CALL { ... } IN TRANSACTIONS'结构),因此这显然是一个死胡同。
在2022年5月31日发布的Neo4j AuraDB Office Hours中,他们尝试在AuraDB中使用相同的功能。 它对他们也不起作用,尽管行为与我在Neo4j Community中观察到的不同。 我猜他们会在某个时候解决这个问题,感觉像是一个错误,但至少现在它又证实了'CALL { ... } IN TRANSACTIONS'不是前进的方法。
选项3:删除数据目录-适用于任何大小的数据集
这是最简单、最直接的机制,实际上也有效:
  • 停止服务器
  • 手动删除数据目录
  • 重新启动服务器
以下是它的样子:
% ./bin/neo4j stop
% rm -rf data/databases data/transactions
% ./bin/neo4j start

这很简单。你可以编写一个脚本来捕获这个作为一个单一的命令。
选项4:在代码中删除 - 可以处理任何大小的数据集
下面是一个最小的Java程序,处理所有节点和关系的删除,无论有多少个。手动删除选项可以正常工作,但我需要一种在代码中删除所有节点和关系的方法。这适用于Neo4j Community 4.4.3,由于我仅使用基本功能(没有扩展),我认为这也适用于其他范围的Neo4j版本,以及可能是AuraDB。
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.Session;

public static void main(String[] args) throws InterruptedException {
    String boltUri = "...";
    String user = "...";
    String password = "...";
    Session session = GraphDatabase.driver(boltUri, AuthTokens.basic(user, password)).session();

    int count = 1;
    while (count > 0) {
        session.executeWrite(tx -> tx.run("MATCH (x) WITH x LIMIT 1000 DETACH DELETE x"));
        count = session.executeWrite(tx -> tx.run("MATCH (x) RETURN COUNT(x)").single().values().get(0).asInt());
    }
}

2023年1月,确认选项2仍然无法正常工作。建议使用“auto:”前缀也无效: https://community.neo4j.com/t5/neo4j-graph-platform/best-practice-for-replacement-of-using-periodic-commit-to-call/td-p/53853 - JonoMac

0

我进行了几次测试,最佳组合是

`call apoc.periodic.iterate("MATCH p=()-[r]->() RETURN r,p LIMIT 5000000;","DELETE r;", {batchSize:10000, parallel: true}`)

(此代码在3251秒内删除了300,000,000个关系)

值得注意的是,使用“parallel”参数会显着缩短时间。

适用于Neo4j 4.4.1 AWS EC2:m5.xlarge

neo4j:
  resources:
    memory: 29000Mi
  configs:
    dbms.memory.heap.initial_size: "20G"
    dbms.memory.heap.max_size: "20G"
    dbms.memory.pagecache.size: "5G"

你是不是想说“去掉并行处理”?不过,以上设置也可能取决于具体机器的规格。 - George Birbilis
1
通过“采用并行处理”的方式,我指的是从“apoc”函数中删除“parallel”参数会导致其性能大幅下降。 - Ernandes Junior

0
只是添加一个更新,因为我今天需要这样做,而且不想删除数据库。
:auto MATCH (n) CALL { WITH n DETACH DELETE n } IN TRANSACTIONS OF 50000 ROWS

0
optional match (n)-[p:owner_real_estate_relation]->() with n,p LIMIT 1000 delete p

在测试运行中,删除了50000个关系,在589毫秒后完成。


1
在Stack Overflow上,仅提供代码的答案并不是特别有帮助的,因此不被鼓励。请更新您的答案以解释它是如何解决问题的,以及为什么它可能比已接受和投票的答案更好。 - FluffyKitten
1
实际上,如果不与其他替代方案在同一台机器上完成所需的时间进行比较(每次使用相同的初始数据库),则完成信息的时间并不是非常有用的。 - George Birbilis
同时,:owner_real_estate_relation与问题中的“all”关系不匹配。 - George Birbilis

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