使用gremlin javascript语言变体的amazon neptune中的ConcurrentModificat



我正在尝试使用promise.all()检查并在块中插入1000个顶点。代码如下:

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。需要帮助来修复/改进此问题。

我不太确定您正在使用的数据和参数,但我需要对您的查询进行一些修改,使其能够使用我手头的数据集(航线(,如下所示。我这样做是为了帮助我思考您的查询在做什么。我不得不更改第二个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等待允许另一个运行而产生,那么如果前一个prompt在数据库中已经有锁,那么下一个promet可能会失败,而下一个promise也需要锁。在您的情况下,因为coalesce引用了具有给定标签和属性的所有顶点,这可能会导致获取冲突的锁。如果在每次for循环迭代后使用await,而不是在一个大的Promise.all中在最后完成所有操作,也许效果会更好。

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

编辑于2021-11-17

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

最新更新