【问题标题】:How can I optimise a Neo4j MERGE query on a node with many relationships?如何在具有许多关系的节点上优化 Neo4j MERGE 查询?
【发布时间】:2015-09-04 23:23:14
【问题描述】:

我有一个带有许多传出关系的节点的图。随着我添加更多关系,添加新的传出关系所需的时间会减少。降级似乎是由于检查关系是否不存在所花费的时间(我正在使用 MERGE 添加关系)。

关系的目标节点本身很少有关系。有什么方法可以强制 Neo4j 从目标节点而不是源节点检查关系是否存在?

这里是重现问题的测试脚本。它创建一个 id 为 0 的节点,然后是 1000 个通过HAS 关系连接到节点 0 的节点。随着节点的增加,执行时间线性增加。

CREATE CONSTRAINT ON (n:Node) ASSERT n.id IS UNIQUE

UNWIND RANGE(1,1000) AS i
MERGE (from:Node { id: 0 })
MERGE (to:Node { id: i})
MERGE (from)-[:HAS]->to

添加1001个标签,创建1001个节点,设置1001个属性,创建 1000 个关系,语句在 3496 毫秒内执行。

UNWIND RANGE(1001,2000) AS i
MERGE (from:Node { id: 0 })
MERGE (to:Node { id: i})
MERGE (from)-[:HAS]->to

添加1000个标签,创建1000个节点,设置1000个属性,创建 1000 个关系,语句在 7030 毫秒内执行。

UNWIND RANGE(2001,3000) AS i
MERGE (from:Node { id: 0 })
MERGE (to:Node { id: i})
MERGE (from)-[:HAS]->to

添加1000个标签,创建1000个节点,设置1000个属性,创建 1000 个关系,语句在 10489 毫秒内执行。

UNWIND RANGE(3001,4000) AS i
MERGE (from:Node { id: 0 })
MERGE (to:Node { id: i})
MERGE (from)-[:HAS]->to

添加1000个标签,创建1000个节点,设置1000个属性,创建 1000 个关系,语句在 14390 毫秒内执行。

如果使用CREATE 而不是MERGE,性能会好很多。我不能使用CREATE,因为我想确保关系是唯一的。

UNWIND RANGE(4001,5000) AS i
MERGE (from:Node { id: 0 })
MERGE (to:Node { id: i})
CREATE (from)-[:HAS]->to

添加1000个标签,创建1000个节点,设置1000个属性,创建 1000 个关系,语句在 413 毫秒内执行。

注意:使用 Neo4j v2.2.2 测试

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

    这是因为 cypher 还不够聪明,无法在执行合并时使用节点的度数。在用于读取的 COST 优化器中,它已经更聪明了,但是对于更新,使用旧的 RULE 优化器。

    在玩了一段时间后失败了 * 改变 from & to 的顺序 * 使用CREATE UNIQUE 而不是MERGE * 尝试使用在 COST 中使用 get-degree 的路径表达式

    我记得shortestPath实际上考虑了学位,也是从左到右

    所以我尝试将它与CREATE 结合起来,效果非常好, 这是 100.000 个节点的示例。

    neo4j-sh (?)$ CREATE CONSTRAINT ON (n:Node) ASSERT n.id IS UNIQUE;
    +-------------------+
    | No data returned. |
    +-------------------+
    Constraints added: 1
    1054 ms
    neo4j-sh (?)$ 
    neo4j-sh (?)$ UNWIND RANGE(0,100000) AS i CREATE (to:Node { id: i});
    +-------------------+
    | No data returned. |
    +-------------------+
    Nodes created: 100001
    Properties set: 100001
    Labels added: 100001
    2375 ms
    neo4j-sh (?)$ 
    neo4j-sh (?)$ 
    neo4j-sh (?)$ MATCH (from:Node { id: 0 })
    > UNWIND RANGE(1,100000) AS i
    > MATCH (to:Node { id: i})
    > WHERE shortestPath((to)<-[:HAS]-(from)) IS NULL
    > CREATE (from)-[:HAS]->(to);
    +-------------------+
    | No data returned. |
    +-------------------+
    Relationships created: 100000
    2897 ms
    neo4j-sh (?)$ 
    neo4j-sh (?)$ 
    neo4j-sh (?)$ MATCH (from:Node { id: 0 })
    > UNWIND RANGE(1,100000) AS i
    > MATCH (to:Node { id: i})
    > WHERE shortestPath((to)<-[:HAS]-(from)) IS NULL
    > CREATE (from)-[:HAS]->(to);
    +--------------------------------------------+
    | No data returned, and nothing was changed. |
    +--------------------------------------------+
    2360 ms
    

    【讨论】:

    • 谢谢,这看起来很有希望。我会测试并告诉你它是怎么回事。
    • 我已经对此进行了测试,它为我们带来了巨大的性能提升。期待查询计划器何时可以自动进行此优化。再次感谢迈克尔 :)
    猜你喜欢
    • 2017-07-03
    • 2016-01-25
    • 2014-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多