优化大量现有节点上的关系创建

时间:2017-11-06 03:04:44

标签: neo4j cypher

我在用于创建大批节点(~1000 - 10000)之间关系的密码查询类似于以下内容。

    "MATCH (startNode1),....,(startNode1000),(endNode1),..(endNode1000)
     WHERE ID(startNode1) = 538035 AND .. ID(startNode1000) = 538035 AND ID(endNode1) = 577 ..ID(endNode1000) = 586 
     CREATE 
     (startNode1)-[r1:`ParameterValue`{Name: "Phi"}]->(endNode1),
     (startNode2)-[r2:`ParameterValue`{Type: "block"}]->(endNode2),..
     (startNode1000)-[r100:`ParameterValue`{FontAngle: "auto"}]->(endNode1000)
     RETURN ID(r1), ID(r2), ..... ID(r1000)"

我正在使用官方java neo4j bolt驱动程序来运行cypher查询,平均而言,上面的cypher命令大约需要 15 秒,这不适合我的应用程序。

我的问题是:

  1. 有没有明显的优化我错过了捆绑我的 cypher查询这种方式?
  2. 一般来说,循环是一个好习惯 在节点上创建关系而不是捆绑它们?
  3. 我是新手,所以非常欢迎任何建议。谢谢!

2 个答案:

答案 0 :(得分:3)

  

通过这种方式捆绑我的密码查询,我是否遗漏了任何明显的优化?

是。有问题的查询使得查询优化器和执行引擎的工作非常困难。如果您转到Web浏览器并使用EXPLAIN运行查询计划,它将向您显示此查询计划需要巨大的元组,而不是构建引擎来处理的。

  

一般来说,循环节点创建关系比捆绑它们是一个好习惯吗?

循环是一个很好的方向。实际上,您可以进行多种优化:

  1. [startNode, endNode, relationshipProperties]三元组的集合作为单个参数传递给驱动程序并UWIND

  2. 使用SET relationship_variable = map_variable construct初始化关系的属性。

  3. 或者,您可能希望使用collect方法在列表中返回结果ID,但这通常不是必需的,因为驱动程序返回可迭代结果。

  4. 这些技巧包含在此查询中:

    UNWIND $rels AS rel
    WITH
      rel[0] AS startNodeId,
      rel[1] AS endNodeId, 
      rel[2] AS relationshipProperties
    MATCH (startNode:SomeLabel), (endNode:SomeLabel)
    WHERE ID(startNode) = startNodeId
      AND ID(endNode) = endNodeId
    CREATE (startNode)-[r:`ParameterValue`]->(endNode1)
    SET r = relationshipProperties
    WITH collect(ID(r)) AS relationshipIds
    RETURN relationshipIds
    

    在客户端,您应该使用StatementRunner.run(statementTemplate, statementParameters) method传递参数。只需一张rels的单个键和三元素列表列表的地图。您可以使用一个好的集合库以简洁的方式表达这一点,例如,Guava' immutable collections

    Map<String, Object> parameters =
      ImmutableMap.of("rels",
        ImmutableList.of(
          ImmutableList.of(1, 2, ImmutableMap.of("prop1", "value1", "prop2", false)),
          ImmutableList.of(3, 4, ImmutableMap.of(...)),
        ...
      )
    );
    StatementRunner.run("UNWIND ...", parameters);
    

    注1。 Cypher语言允许您将节点和关系作为参数传递。但是,这仅适用于嵌入式版本和not in the client-server setup,因此您更适合传递ID。

    注2。话虽如此,传递内部ID是不好的。虽然它适用于大多数原型,但您可能需要考虑避免使用它们并提供您自己的标识符。请参阅Best and Worst Practices with Node IDs

    注3。您也可以使用地图来表示要创建的关系,而不是使用三元组。这样,您将它们作为Map从Java传递,即,您的列表将包含地图:

    ImmutableMap.of("startNode", 1, "endNode", 2, "relationshipProperties", ImmutableMap.of("prop1", "value1", "prop2", true))
    

    然后,您可以将值称为rel.startNoderel.endNoderel.relationshipProperties。这使查询更易读,更易于维护,但通常不值得麻烦。

答案 1 :(得分:-3)

您实际上可以使用cypher

创建关系
MATCH (u:User {username:'admin'}), (r:Role {name:'ROLE_WEB_USER'})
CREATE (u)-[:HAS_ROLE]->(r)

这只是我们有一个用户节点的例子,我们正在创建一个带有ROLE的关系。

以下是文档的链接。 https://neo4j.com/docs/developer-manual/current/cypher/clauses/create/#create-create-a-relationship-between-two-nodes

我不认为以上是正确的方法