You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gremlin JS操作Amazon Neptune批量插入顶点报ConcurrentModificationException

异常原因
  • Promise.all会并行触发所有分块的写查询,支持事务的图数据库(如JanusGraph、Neo4j等)默认不支持无锁的并发写入操作,多个写请求同时操作索引/顶点分区时就会抛出ConcurrentModificationException
  • 你在全局复用了allVertices遍历实例,多个并发查询会同时修改这个遍历的内部状态,也会引发执行异常
优化修复方案

核心逻辑是把并行执行改成串行执行,同时调整遍历实例的生成逻辑,避免状态复用:

  1. 移除Promise.all并行逻辑,改为逐个await执行分块查询
  2. 把addV遍历的生成放到每个分块的循环内部,每次查询生成独立的遍历实例
  3. 可根据实际数据库负载调整分块大小,推荐调整到10~50的区间,减少请求次数同时避免单次查询过大

修复后代码如下:

public async createManyByKey(label: string, key: string, properties: object[]): Promise<T[]> {
    const result: T[] = [];
    const propKeys: Array<string> = Object.keys(properties[0]);
    // 可根据实际性能调整分块大小
    const chunkedProperties = chunk(properties, 20);
    
    for(const chunk of chunkedProperties){
        // 每个分块生成独立的addV遍历,避免状态复用
        const addVTraversal = __.addV(label);
        for(const propKey of propKeys){
            addVTraversal.property(propKey, __.select(propKey));
        }
        // 串行执行每个分块的查询
        const chunkResult = await this.g.inject(chunk)
           .unfold().as('data')
           .coalesce(
                __.V().hasLabel(label).where(eq('data')).by(key).by(__.select(key)), 
                addVTraversal
            )
           .toList();
        result.push(...chunkResult);
    }
    return result;
}
额外优化建议
  • 如果数据库支持配置写重试机制,可以给查询添加自动重试逻辑,遇到并发异常时自动重试失败的分块
  • 插入前可以先批量查询已存在的顶点,过滤掉不需要插入的记录,减少写操作的数量

内容的提问来源于stack exchange,提问作者codegutsy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 21:15:01