我在用于创建大批节点(~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 秒,这不适合我的应用程序。
我的问题是:
我是新手,所以非常欢迎任何建议。谢谢!
答案 0 :(得分:3)
通过这种方式捆绑我的密码查询,我是否遗漏了任何明显的优化?
是。有问题的查询使得查询优化器和执行引擎的工作非常困难。如果您转到Web浏览器并使用EXPLAIN
运行查询计划,它将向您显示此查询计划需要巨大的元组,而不是构建引擎来处理的。
一般来说,循环节点创建关系比捆绑它们是一个好习惯吗?
循环是一个很好的方向。实际上,您可以进行多种优化:
将[startNode, endNode, relationshipProperties]
三元组的集合作为单个参数传递给驱动程序并UWIND
。
使用SET relationship_variable = map_variable
construct初始化关系的属性。
或者,您可能希望使用collect
方法在列表中返回结果ID,但这通常不是必需的,因为驱动程序返回可迭代结果。
这些技巧包含在此查询中:
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.startNode
,rel.endNode
和rel.relationshipProperties
。这使查询更易读,更易于维护,但通常不值得麻烦。
答案 1 :(得分:-3)
您实际上可以使用cypher
创建关系MATCH (u:User {username:'admin'}), (r:Role {name:'ROLE_WEB_USER'})
CREATE (u)-[:HAS_ROLE]->(r)
这只是我们有一个用户节点的例子,我们正在创建一个带有ROLE的关系。
我不认为以上是正确的方法