0

我正在尝试使用promise.all(). 代码如下:

public async createManyByKey(label: string, key: string, properties: object[]): Promise<T[]> {
    const promises = [];
    const allVertices = __.addV(label);
    const propKeys: Array<string> = Object.keys(properties[0]);
     
    for(const propKey of propKeys){
      allVertices.property(propKey, __.select(propKey));
    }

    const chunkedProperties = chunk(properties, 5); // [["demo-1", "demo-2", "demo-3", "demo-4", "demo-5"], [...], ...]
    
    for(const property of chunkedProperties){
        const singleQuery = this.g.withSideEffect('User', property)
       .inject(property)
       .unfold().as('data')
       .coalesce(__.V().hasLabel(label).where(eq('data')).by(key).by(__.select(key)), allVertices).iterate();

       promises.push(singleQuery);
     }

    const result = await Promise.all(promises);

    return result;
  }

此代码引发 ConcurrentModificationException。需要帮助来修复/改进此问题。

4

1 回答 1

0

我不太确定您正在使用的数据和参数,但我需要稍微修改您的查询以使其与我方便的数据集(空中航线)一起使用,如下所示。我这样做是为了帮助我思考您的查询在做什么。我不得不改变by第二步。我不确定那是如何工作的。

gremlin> g.inject(['AUS','ATL','XXX']).unfold().as('d').
......1>   coalesce(__.V().hasLabel('airport').limit(10).
......2>            where(eq('d')).
......3>              by('code').
......4>              by(), 
......5>            constant('X'))  
==>v['3']
==>v['1']
==>X 

虽然像这样的查询在隔离时运行良好,但一旦您开始运行多个异步 promise(包含查询中的变异步骤),可能会发生一个 promise 尝试访问被另一个 promise 锁定的图的一部分。即使如果一个承诺由于 IO 等待允许另一个运行而产生,我认为执行比真正的“并行”更“并发”,但如果先前的承诺已经在数据库中锁定下一个承诺也可能会失败需要。在您的情况下,因为您有一个coalesce引用具有给定标签和属性的所有顶点,这可能会导致冲突锁定。如果您await在每次for循环迭代之后而不是在一个大的Promise.all.

要记住的另一件事是,无论如何,此查询都会有些昂贵,因为每次循环迭代V都会发生五次中间遍历(在您的示例中) 。for这是因为unfold注入的数据是从大小为 5 的块中获取的,因此会产生五个遍历器,每个遍历器都从查看V.

2021-11-17 编辑

正如评论中所讨论的,我怀疑最佳路径实际上是使用多个查询。第一个查询只是g.V(id1,id2,...)对您可能要添加的所有 ID 执行 a。让它返回找到的 ID 列表。从要添加的集合中删除那些。接下来将添加部分分成批次并在没有的情况下进行coalesce,因为您现在知道这些元素不存在。这很可能是减少锁定和避免 CME(异常)的最佳方法。除非其他人可能也试图并行添加它们,否则我认为我会采用这种方法。

于 2021-11-11T20:30:21.473 回答