Neo4j中批量更新关系属性的性能较慢

Neo4j中批量更新关系属性的性能较慢,neo4j,cypher,py2neo,Neo4j,Cypher,Py2neo,我正在努力有效地批量更新Neo4j中的关系属性。目标是更新约500000个关系(每个关系大约有3个属性),我将其分为1000个批次,并在一个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 但是,每批

我正在努力有效地批量更新Neo4j中的关系属性。目标是更新约500000个关系(每个关系大约有3个属性),我将其分为1000个批次,并在一个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
但是,每批1000个节点大约需要60秒。对于
:Entity
标签,UUID属性上存在一个索引,即我以前运行过

CREATE INDEX ON :Entity(uuid)
这意味着根据查询计划匹配关系是非常高效的

总共有6次db命中,查询在大约150毫秒内执行。我还在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)
请尝试以下查询:

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;

它用于强制对两个
实体
节点进行索引查找,然后是一个运算符,该运算符的性能应该比查询计划中显示的and
筛选器
运算符更高。

@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)
返回

请注意,使用索引提示将DB命中数从6减少到4。对于上下文,我们有多个节点标签(和索引),尽管每个节点都有
:Entity
标签