带有 APOC 的 Neo4j:运行 使用 apoc.perodic.commit 大块创建

Neo4j with APOC: running large CREATE in chunks using apoc.perodic.commit

使用 Neo4j 3.3.4(可通过 neo4j console 命令移植),我试图在 "Device" 和 "Location" 节点之间创建基于关于两者的属性。一个设备有一个"OwnedByLocation"属性;一个位置最多可以有 14 个独立的名称属性。这很简单,但问题是我有大约 8,000 个位置和 350 万个设备,因此尽管我的堆大小为 24GB,但标准查询 运行s 内存不足。

我进行了一些搜索,找到了 ,并安装了 APOC 插件,这样我就可以使用 periodic.commit 将查询拆分成块。我尝试的命令如下,但每当我 运行 它时,浏览器将在几分钟后断开与数据库的连接,并且不会重新连接。我不知道 Neo4j 是否仍然 运行ning,但似乎没有形成任何关系(并且肯定应该匹配)。

call apoc.periodic.commit("
match (loc:Location)
WHERE NOT (loc)-[:OwnsDevice]->(:dev)
WITH loc LIMIT {limit}
MATCH (dev:Device)
WHERE dev.OwnedByLocation contains loc.Name1
OR dev.OwnedByLocation contains loc.Name2 
OR dev.OwnedByLocation contains loc.Name3 
OR dev.OwnedByLocation contains loc.Name4 
OR dev.OwnedByLocation contains loc.Name5 
OR dev.OwnedByLocation contains loc.Name6 
OR dev.OwnedByLocation contains loc.Name7 
OR dev.OwnedByLocation contains loc.Name8 
OR dev.OwnedByLocation contains loc.Name9 
OR dev.OwnedByLocation contains loc.Name10 
OR dev.OwnedByLocation contains loc.Name11 
OR dev.OwnedByLocation contains loc.Name12 
OR dev.OwnedByLocation contains loc.Name13 
OR dev.OwnedByLocation contains loc.Name14
CREATE (loc)-[r:OwnsDevice {Source:'Legacy Database'}]->(dev)
RETURN count(*)
",{limit:10000})

有没有人有更好的建议(使用 apoc.period.commit 或其他方式)?没有支付 Amazon Web Services 1500 美元租用超级计算机,我就没主意了。非常感谢您提供的任何帮助。

1) 我认为问题在于查询中存在错误 - 您正在查看与带有标签 :dev 的节点没有连接的模式,但您创建了一个连接标记为 :Device 的节点,因此查询永远不会结束,因为它不断 returns 一个大于零的数字:

WHERE NOT (loc)-[:OwnsDevice]->(:dev)
...
MATCH (dev:Device)
...
CREATE (loc)-[r:OwnsDevice {Source:'Legacy Database'}]->(dev)
RETURN count(*) // Always greater than zero

2) 您可以使查询更紧凑:

CALL apoc.periodic.commit("
  MATCH (loc:Location)
  WHERE NOT (loc)-[:OwnsDevice]->(:Device)
  WITH loc LIMIT {limit}
  MATCH (dev:Device)
  WHERE ANY(propName IN KEYS(loc) WHERE propName IN {propNames} AND 
                                        dev.OwnedByLocation CONTAINS loc[propName]
        ) 
  MERGE (loc)-[r:OwnsDevice {Source:'Legacy Database'}]->(dev)
  RETURN count(*)
", {limit:10000,
    propNames: ["Name1", "Name2", "Name3", "Name4", "Name5", "Name6", "Name7", "Name8", "Name9", "Name10", "Name11", "Name12", "Name13", "Name14",
})

除了@stdob-- 提到的错误之外,您还有一些其他主要问题。

您只有 8K 个位置,但您的定期提交使用了 10K 的限制,因此它对您没有任何作用(除了会进一步减慢您的速度)。因此,如果您尝试使用下限(比如 1K 甚至 500),您 可能会 取得一些进展 -- 但它仍然会很慢。

您的查询引发了几​​个危险信号,表明您可以通过更改数据模型获得更好的性能。现在,您无法利用索引和关系的力量来查找设备。这些是 neo4j 中可用的最强大的工具。

例如,您的 MATCH (dev:Device) WHERE dev.OwnedByLocation contains loc.Name1 ... 子句强制 neo4j 扫描所有 350 万台设备每个位置。 (更不用说对于每个设备,您正在使用 CONTAINS 测试 14 次。是否需要 CONTAINS,或者您可以使用更便宜的相等测试吗?此外,位置的名称是否可以存储在一个数组,并且总是恰好有 14 个名字吗?)

以下是我设计您的数据模型的方式(假设我们可以对名称使用相等性测试):

(:Location {id: 123})-[:HAS_NAME]->(:LocName {name: 'Foo'})

(:Device {id: 765, ownedByLocName: 'Foo'})

我也会创建这个索引:

CREATE INDEX ON :Device(ownedByLocName);

这里是创建所有 OWNS_DEVICE 关系的新查询:

MATCH (loc:Location)
WHERE NOT (loc)-[:OWNS_DEVICE]->()
WITH loc LIMIT {limit}
MATCH (loc)-[:HAS_NAME]->(ln:LocName)
MATCH (dev:Device)
WHERE dev.ownedByLocName = ln.name
CREATE (loc)-[:OWNS_DEVICE {source:'Legacy Database'}]->(dev)
RETURN count(*)

以上查询只需要进行快速(索引)查找即可找到与每个位置名称匹配的所有设备。