【问题标题】:Slow performance bulk updating relationship properties in Neo4jNeo4j 中性能缓慢的批量更新关系属性
【发布时间】:2017-04-05 04:16:49
【问题描述】:

我正在努力有效地批量更新 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 个数据库命中,查询在大约 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)

【问题讨论】:

    标签: neo4j cypher py2neo


    【解决方案1】:

    试试这个查询:

    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 强制对 both Entity 节点进行索引查找,然后使用 Expand(Into) 运算符,这应该比 Expand(All)Filter 运算符更高效您的查询计划。

    【讨论】:

      【解决方案2】:

      @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 标签。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-10
        • 2016-08-04
        • 2017-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多