我正在尝试使用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。需要帮助来修复/改进此问题。
发布于 2021-11-11 20:30:21
我不太确定您正在使用的数据和参数,但我需要对您的查询进行一些修改,使其能够使用我手边的数据集(空中路线),如下所示。我这样做是为了帮助我想清楚你的查询在做什么。我不得不更改第二个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锁定的图的一部分。即使我认为如果一个promise由于IO等待允许另一个promise运行而导致的执行更多地是“并发”而不是真正的“并行”,如果前一个promise已经在数据库中具有下一个promise也需要的锁,那么下一个promise可能会失败。在您的示例中,由于您有一个引用具有给定标签和属性的所有顶点的coalesce,这可能会导致采用冲突的锁。也许,如果你在每次for循环迭代后执行await,而不是在一个大的Promise.all中完成所有这些工作,效果会更好。
要记住的另一件事是,这个查询无论如何都会有一些开销,因为对于每个for循环迭代,中间遍历V将发生五次(在您的示例中)。这是因为注入数据的unfold取自大小为5的块,因此会产生5个遍历,每个遍历都从查看V开始。
编辑于2021-11-17
正如评论中所讨论的,我怀疑最优的路径实际上是使用多个查询。第一个查询只是对您可能要添加的所有ID执行一个g.V(id1,id2,...)。让它返回找到的ID列表。从要添加的集合中删除这些。接下来,将添加部分拆分成批处理,不使用coalesce,因为您现在知道这些元素并不存在。这很可能是减少锁定和避免CME(异常)的最佳方法。除非其他人也在尝试并行添加它们,否则我想我会采用这种方法。
https://stackoverflow.com/questions/69932798
复制相似问题