database - 避免跨产品 APOC 查询的方法(使用 hashmap?)?
问题描述
我目前有一个Neo4J
数据库,它的数据结构简单,由大约 4 亿个组成(:Node {id:String, refs:List[String]})
,具有两个属性: An id
,它是一个字符串,以及refs
,它是一个字符串列表。
我需要搜索所有这些节点以识别它们之间的关系。如果一个节点在另一个鼻子id
的列表中,则存在这些定向关系。ref
一个简单的查询可以完成我想要的(但太慢了):
MATCH (a:Node), (b:Node)
WHERE ID(a) < ID(b) AND a.id IN b.refs
CREATE (b)-[:CITES]->(a)
我可以使用apoc.periodic.iterate
,但查询仍然太慢:
CALL apoc.periodic.iterate(
"MATCH (a:Node), (b:Node)
WHERE ID(a) < ID(b)
AND a.id IN b.refs RETURN a, b",
"CREATE (b)-[:CITES]->(a)",
{batchSize:10000, parallel:false,iterateList:true})
关于如何有效地建立这个数据库和关系的任何建议?当我第一次将节点添加到数据库时,我对创建哈希表的想法很模糊,但我不确定如何实现这一点,尤其是在 Neo4j 中。
谢谢你。
解决方案
如果您首先在 上创建索引:Node(id)
,如下所示:
CREATE INDEX ON :Node(id);
那么这个查询应该能够利用索引快速找到每个a
节点:
MATCH (b:Node)
UNWIND b.refs AS ref
MATCH (a:Node)
WHERE a.id = ref
CREATE (b)-[:CITES]->(a);
目前,Cypher 执行计划程序不支持在直接比较 2 个属性的值时使用索引。在上面的查询中,WHERE
子句将属性与变量进行比较,因此可以使用索引。
省略了ID(a) < ID(b)
测试,因为您的问题没有说明需要以这种方式订购本机节点 ID。
[更新 1]
如果您想并行运行创建步骤,请尝试使用 APOC 过程apoc.periodic.iterate:
CALL apoc.periodic.iterate(
"MATCH (b:Node) UNWIND b.refs AS ref RETURN b, ref",
"MATCH (a:Node {id: ref}) CREATE (b)-[:CITES]->(a)",
{batchSize:10000, parallel:true})
传递给过程的第一个 Cypher 语句只返回每个b
/ref
对。第二条语句(并行运行)使用索引来查找a
节点并创建关系。这种工作分工将更昂贵的处理放在并行线程中运行的语句中。该iterateList: true
选项被省略,因为我们(可能)希望第二条语句为每个b
/ref
对并行运行。
[更新 2]
如果并行执行尝试将关系添加到相同的节点,您可能会遇到死锁错误(因为每个并行事务将尝试写锁定每个新关系的结束节点)。为避免仅涉及b
节点的死锁,您可以执行以下操作以确保b
不并行处理节点:
CALL apoc.periodic.iterate(
"MATCH (b:Node) RETURN b",
"UNWIND b.refs AS ref MATCH (a:Node {id: ref}) CREATE (b)-[:CITES]->(a)",
{batchSize:10000, parallel:true})
但是,如果并行执行可以尝试写锁定相同的a
节点(或者如果任何b
节点也可以用作a
节点),这种方法仍然容易出现死锁。但至少希望这个附录能帮助你理解这个问题。
[更新 3]
由于这些死锁是依赖于多个并行执行尝试同时锁定相同节点的竞争条件,因此您可以通过在失败时重试“内部语句”来解决此问题。您还可以尝试减小批量大小,以减少多个并行重试在时间上重叠的可能性。像这样的东西:
CALL apoc.periodic.iterate(
"MATCH (b:Node) RETURN b",
"UNWIND b.refs AS ref MATCH (a:Node {id: ref}) CREATE (b)-[:CITES]->(a)",
{batchSize: 1000, parallel: true, retries: 100})
推荐阅读
- arrays - 带有数组访问的 for 循环的运行时间
- vue.js - v-switch 在检查时返回 False 值
- python - 根据元组将值插入像素
- javascript - 将秒输出更改为分钟和小时
- mysql - 如果它们在sql中共享相同的id值,如何将值组合在一起
- django - Django 从 MultipleChoiceField 获取已清理的数据
- c# - 远程桌面 Active X 控件未连接
- dart - 如何在 Dart 中获取顶级函数的元数据
- mailgun - Linode 域管理器中的 MailGun TXT 记录
- php - Codeiniter Rest Server - 无法获取通过发布请求发送的数据