从Neo4j的大量节点中删除属性

3

我有一个包含数百万个人类型节点的neo4j数据库,我想删除所有person节点的特定属性。我尝试使用match查询来实现它,但它正在扫描所有节点。

这是我尝试过的查询:

MATCH (p:Person)
REMOVE p.fatherName

还有没有其他快速替代这个查询的方法?


这个查询不应该扫描所有节点(AllNodesScan),它只应该获取带有该标签的节点(NodeByLabelScan)。如果实际上正在扫描所有节点,请分享EXPLAINPROFILE的结果(请参见https://dev59.com/kWIj5IYBdhLWcg3wGRmN#31534005)。 - jjaderberg
是的,你关于NodeByLabelScan的说法是正确的,但我只有一种类型的节点,而且所有的节点都有这个标签。这就是为什么我说它正在扫描每一个节点。 - Muhammad Adnan
好的,在Cypher中声明该操作没有更简单的方法了。为什么速度在你的情况下是个问题?你需要重复执行这个操作还是只是一次性的建模维护操作?你可以通过Java API获得更好的性能,可以通过嵌入数据库或使用服务器扩展来实现,但你也可以通过分页查询并重复运行它来解决问题。 - jjaderberg
实际上,它也占用了很多资源,并且消耗了我系统的所有内存,大约8GB左右,大约1小时后,它会给我一个gcc内存不足的异常。这就是为什么我一直在尝试找出一些可行的解决方案。 - Muhammad Adnan
在这种情况下,分页查询应该有所帮助,MicTech在他的答案中解释了如何做到这一点。尝试设置10k到100k之间的限制以找到一个可行的方案,然后运行查询,直到它不再显示任何已删除的属性。 - jjaderberg
1个回答

5

无法通过Cypher查询来提高该查询的性能。

您可以尝试避免没有fatherName属性的节点。

MATCH (p:Person)
WHERE HAS (p.fatherName)
REMOVE p.fatherName

此外,添加LIMIT并多次运行查询可能会有所帮助。
MATCH (p:Person)
WHERE HAS (p.fatherName)
WITH p LIMIT 100000
REMOVE p.fatherName

我建议您编写非托管扩展来删除该属性。
例如:
Label nodeLabel = DynamicLabel.label("Person");
String propertyName = "fatherName";

try(Transaction tx = database.beginTx()) {
    final ResourceIterator<Node> people = database.findNodes(nodeLabel);

    for (Node person : IteratorUtil.asCollection(people)) {
        if (person.hasProperty(propertyName)) {
            person.removeProperty(propertyName);
        }
    }

    tx.success();
}

如果只是一次性操作,使用Java嵌入式可能更容易。如果利用服务器扩展,也许可以将其泛化以适用于任何属性/标签对?+1 - jjaderberg

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