我有一个这样的顶点
Vertex1
{
name:'hello',
id: '2',
key: '12345',
col1: 'value1',
col2: 'value2',
.......
}
Vertex2,Vertex3,..... Vertex200K
{
name:'hello',
id: '1',
key: '12345',
col1: 'value1',
col2: 'value2',
.......
}
密码查询
MATCH (a:Dense1) where a.id <> "1"
WITH a
MATCH (b:Dense1) where b.id = "1"
WITH a,b
WHERE a.key = b.key
MERGE (a)-[:PARENT_OF]->(b)
最终结果应为 Vertex1 ,度数应为 200K ,因此,应存在20万个关系。但是,上面的查询花费大量时间,几乎使吞吐量降低到500 /秒。关于如何更快地建立关系/优势的任何想法?
当我运行配置文件时,上面的密码查询将永远运行并且不会返回,因此我将大小从200K减小到20K,这是配置文件向我显示的内容。
答案 0 :(得分:1)
鉴于您的内存限制以及与您的关系的合并相关的高数据库命中率,可能是您试图在单个事务中合并200k关系的问题。您可能应该使用apoc.periodic.iterate()中的APOC Procedures进行批量处理:
CALL apoc.periodic.iterate("
MATCH (a:Dense1)
WHERE a.id <> '1'
MATCH (b:Dense1)
WHERE b.id = '1' AND a.key = b.key
RETURN a, b",
"MERGE (a)-[:PARENT_OF]->(b)",
{}) YIELD batches, total, errorMessages
RETURN batches, total, errorMessages
这应该一次批量合并10k。
此外,如果您偶然发现这些关系尚不存在,请使用CREATE而不是MERGE,它将更快。
答案 1 :(得分:0)
在用于匹配的属性上创建索引。
这里有MEStreamSinkRequestSample
和id
属性。
您可以使用以下查询创建索引:
key
这是提高性能的第一步。 您可以使用其他一些技巧来进一步改进。
答案 2 :(得分:0)
您可以尝试运行
MATCH (b:Dense1) where b.id <> "1"
WITH b, b.key AS bKey
MATCH (a:Dense1) where a.id = "1" AND a.key = bKey
MERGE (a)-[:PARENT_OF]->(b)
确保您拥有id和key的索引后?
另外,我能正确理解id不是唯一的,并且您有1个id = 2的节点和200k id = 1的节点吗?如果我弄错了,请翻转条件以使第一行返回单个节点,您希望所有关系都进入其中,而第二部分则与所有剩余的200k节点匹配。另外,在合并中,将低密度节点作为第一个节点(因此,这里b将获得200k关系)-如果不正确,则将其反转为(b)<-[:XXX]-(a)
自从我处理大型导入/合并以来已经有一段时间了,但是我记得,显式提取变量(例如bKey)然后可以在索引中进行匹配,并从单个节点(单个或几个b)开始)移到较高(多个a)的位置比使用where子句类似于a.key = b.key的查询的效果更好。
已经说过,一次交易中有20万个关系,并且连接到单个节点,这是很多的,因为只需在索引上进行匹配即可快速找到节点,但是您仍然需要验证所有传出的关系,以查看它们是否已经偶然链接到另一个节点。因此,在创建上一个关系时,需要迭代/检查将近20万个关系。
一个窍门是循环运行批处理,直到没有任何结果创建为止,例如
MATCH (b:Dense1) where b.id = "1"
WITH b, b.key AS bKey
MATCH (a:Dense1) where a.id <> "1" AND a.key = bKey
AND NOT (a) -[:PARENT_OF]-> (b) WITH a,b LIMIT 10000
MERGE (a)-[:PARENT_OF]->(b)
这可能表明,批处理的时间越长,花费的时间就越长-从逻辑上讲是有意义的,因为越走越远,就需要检查b中越来越多的关系。
或者,如其他响应所示,通过APOC进行批处理。
最后-这是正在进行的过程还是DB的一次性设置/初始化?如果仅用于初始加载,则还有更多,更快的选择。