我努力在Neo4j中有效地批量更新关系属性。目标是更新~500,000个关系(每个关系大约有3个属性),我将这些关系分成1,000个批次并在单个Cypher语句中处理,
UNWIND {rows} AS row
MATCH (s:Entity) WHERE s.uuid = row.source
MATCH (t:Entity) WHERE t.uuid = row.target
MATCH (s)-[r:CONSUMED]->(t)
SET r += row.properties
然而,每批1,000个节点大约需要60秒。 :Entity
标签的UUID属性存在索引,即我以前运行过,
CREATE INDEX ON :Entity(uuid)
这意味着根据查询计划匹配关系是非常有效的,
总共有6次db命中,查询在~150 ms内执行。我还在UUID属性上添加了唯一性约束,确保每个匹配只返回一个元素,
CREATE CONSTRAINT ON (n:Entity) ASSERT n.uuid IS UNIQUE
有谁知道如何进一步调试这一点,以了解为什么Neo4j需要这么长时间来处理关系?
请注意,我使用类似的逻辑来更新节点,这些节点的速度要快几个数量级,因此会有更多与之关联的元数据。
供参考我使用Neo4j 3.0.3,py2neo和Bolt。 Python代码块的格式为
for chunk in chunker(relationships): # 1,000 relationships per chunk
with graph.begin() as tx:
statement = """
UNWIND {rows} AS row
MATCH (s:Entity) WHERE s.uuid = row.source
MATCH (t:Entity) WHERE t.uuid = row.target
MATCH (s)-[r:CONSUMED]->(t)
SET r += row.properties
"""
rows = []
for rel in chunk:
rows.append({
'properties': dict(rel),
'source': rel.start_node()['uuid'],
'target': rel.end_node()['uuid'],
})
tx.run(statement, rows=rows)
答案 0 :(得分:2)
尝试此查询:
UNWIND {rows} AS row
WITH row.source as source, row.target as target, row
MATCH (s:Entity {uuid:source})
USING INDEX s:Entity(uuid)
WITH * WHERE true
MATCH (t:Entity {uuid:target})
USING INDEX t:Entity(uuid)
MATCH (s)-[r:CONSUMED]->(t)
SET r += row.properties;
它使用index hints强制对 Entity
个节点进行索引查找,然后使用Expand(Into)
运算符,该运算符应该比{{3}更高效您的查询计划显示的{}和Filter
运算符。
答案 1 :(得分:0)
@ william-lyon我想知道我是否需要WITH * WHERE true
条款?我问的原因是DB命中数从4增加到8,即
PROFILE
MATCH (s:Entity {uuid:row.source})
USING INDEX s:Entity(uuid)
MATCH (t:Entity {uuid:row.target})
USING INDEX t:Entity(uuid)
MATCH (s)-[r:CONSUMED]->(t)
返回
而
PROFILE
MATCH (s:Entity {uuid:row.source})
USING INDEX s:Entity(uuid)
WITH * WHERE true
MATCH (t:Entity {uuid:row.target})
USING INDEX t:Entity(uuid)
MATCH (s)-[r:CONSUMED]->(t)
返回
请注意,使用索引提示会将数据库命中数从6减少到4.对于上下文,我们有多个节点标签(和索引),尽管每个节点都有:Entity
标签。