【问题标题】:Neo4j: how do I delete all duplicate relationships in the database through cypher?Neo4j:如何通过 cypher 删除数据库中的所有重复关系?
【发布时间】:2014-05-24 14:29:09
【问题描述】:

我有一个包含大量节点(1000 万+)的庞大数据库。整个数据库中只有一种关系。但是,有大量节点之间存在重复关系。我目前拥有的是这个 cypher 脚本,它找到所有重复的对,然后是一个运行并清理每个对的 python 脚本(在这些节点之间只留下一个唯一的关系)。

match (a)-[r]->(b) with a,b, count(*) as c where c>1 return a.pageid, b.pageid, c LIMIT 100000;

这对于小型数据库非常有效,但是当我在大型数据库上运行它时,它最终会崩溃,但会出现堆内存不足的异常(越来越多地撞上盒子并没有帮助)。

所以,问题有两个方面: 1)我可以对关系进行任何类型的索引(现在没有),这将有助于加快速度吗? 2)是否有一个密码查询可以(以快速的方式......或至少可靠地)删除数据库中的所有重复关系,为每个节点对(它们之间已经存在关系)只留下一个唯一的关系?

附:我在 ubuntu(12something)AWS 机器上运行 neo4j 2.0.1。

附言我意识到有这个答案:stackoverflow,但是他要问的是更具体的东西(针对 2 个已知节点),并且覆盖完整数据库的答案不再运行(语法更改?)

提前致谢!

【问题讨论】:

  • 只是一些想法:您是否尝试过较小的批次,一次可能 100 个,将它们传递给您的 python 脚本? (不确定您是否需要每次通过获取 100K)您的节点上是否有索引,您可以在其中针对特定节点类型运行此操作,从而减少总节点空间?

标签: python database neo4j


【解决方案1】:

链接的 SO 问题中的 db 全局查询会出现什么错误?尝试用| 替换FOREACH 中的:,这是我能看到的唯一破坏性语法差异。 2.x 表达相同内容的方式可能是

MATCH (a)-[r]->(b)
WITH a, b, TAIL (COLLECT (r)) as rr
FOREACH (r IN rr | DELETE r)

我认为WITH 管道会在没有重复的情况下携带空尾,我不知道循环一个空集合有多昂贵——我的感觉是引入限制的地方是WITH 之后的过滤器,类似于

MATCH (a)-[r]->(b)
WITH a, b, TAIL (COLLECT (r)) as rr
WHERE length(rr) > 0 LIMIT 100000
FOREACH (r IN rr | DELETE r)

由于此查询根本不涉及属性(与您的查询相反,它返回 (a) 和 (b) 的属性),我认为对于像您这样的中等图形而言,它不应该占用太多内存,但是您将不得不尝试限制。

如果内存仍然是一个问题,那么如果有任何方法可以限制节点使用(不涉及属性),这也是一个好主意。如果您的节点可以通过标签区分,请尝试同时运行一个标签的查询

MATCH (a:A)-[r]->(b) //etc..
MATCH (a:B)-[r]->(b) //etc..

【讨论】:

  • FOREACH 怎么知道只杀死额外的并留下 1(例如,如果有 3 个相同的关系,则留下 1 并杀死 2)。只是想在我在 db 上运行它之前了解一下(花了 2 周时间来导入这些数据:-/
  • 先做测试,只需在console.neo4j.org 或其他地方设置一个模拟数据库。原因是您只携带集合的尾部,即除了第一个之外的所有内容,因此第一个将不会被 foreach 触及。
  • 成功了!!!!以前的努力会持续数小时,最终会因一堆“内存不足”异常而崩溃。这件事在 2.5 分钟内完成!!
  • 一年后出现语法错误。 Neo4j 出于某种原因不喜欢LIMIT 100000
【解决方案2】:

这是已接受答案的一个版本,已修复(通过插入 WITH rr 子句)与更新的 neo4j 版本一起使用,并且应该更快(因为它只在需要时创建新的 TAIL 列表):

MATCH (a)-[r]->(b)
WITH a, b, COLLECT(r) AS rr
WHERE SIZE(rr) > 1
WITH rr
LIMIT 100000
FOREACH (r IN TAIL(rr) | DELETE r);

[更新]

如果您只想删除具有相同类型的重复关系,请执行以下操作:

MATCH (a)-[r]->(b)
WITH a, b, TYPE(r) AS t, COLLECT(r) AS rr
WHERE SIZE(rr) > 1
WITH rr
LIMIT 100000
FOREACH (r IN TAIL(rr) | DELETE r);

【讨论】:

    猜你喜欢
    • 2013-10-01
    • 1970-01-01
    • 2022-10-19
    • 1970-01-01
    • 2011-09-13
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    相关资源
    最近更新 更多