在Neo4J 3.5中创建与节点的200K关系要花费很多时间?

时间:2019-07-04 08:53:21

标签: neo4j

我有一个这样的顶点

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,这是配置文件向我显示的内容。

enter image description here

3 个答案:

答案 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)

在用于匹配的属性上创建索引。

这里有MEStreamSinkRequestSampleid属性。

您可以使用以下查询创建索引:

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的一次性设置/初始化?如果仅用于初始加载,则还有更多,更快的选择。