首页 文章

如何在具有多种关系的节点上优化Neo4j MERGE查询?

提问于
浏览
8

我有一个图表,其节点具有许多传出关系 . 随着我添加更多关系,添加新的传出关系所花费的时间会降低 . 退化似乎是由于检查关系尚未存在所花费的时间(我使用MERGE来添加关系) .

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

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

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进行测试

1 回答

  • 10

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

    使用 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
    

相关问题