ConcurrentModificationException в amazon neptune с использованием варианта языка gremlin javascript

Я пытаюсь проверить и вставить 1000 вершин в кусок, используя 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]);


    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. Нужна помощь, чтобы исправить / улучшить эту проблему.

1 ответ

Я не совсем уверен в данных и параметрах, которые вы используете, но мне нужно немного изменить ваш запрос, чтобы заставить его работать с имеющимся у меня набором данных (воздушные маршруты), как показано ниже. Я сделал это, чтобы помочь мне понять, что делает ваш запрос. пришлось менять второй шаг. Я не уверен, как это работало в противном случае.

      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 

Хотя такой запрос отлично работает изолированно, как только вы запускаете несколько асинхронных обещаний (которые содержат изменяющиеся шаги, как в вашем запросе), может случиться так, что одно обещание попытается получить доступ к части графа, которая заблокирована другим. Несмотря на то, что выполнение, которое я считаю, является более «параллельным», чем действительно «параллельным», если одно обещание уступает из-за ожидания ввода-вывода, позволяющего запустить другое, следующее может завершиться неудачно, если предыдущее обещание уже имеет блокировки в базе данных, что следующее обещание также потребности. В вашем случае, когда у вас есть ссылка на все вершины с заданной меткой и свойствами, это потенциально может привести к блокировке конфликтов. Возможно, это сработает лучше, если вы после каждой итерации цикла, а не делать все это в конце в одном большом .

Еще кое-что, о чем следует помнить, это то, что этот запрос будет несколько дорогим, так как промежуточный обход будет происходить пять раз (в случае вашего примера) для каждого итерация цикла. Это потому, что введенных данных берется из кусков размером 5 и, следовательно, порождает пять обходчиков, каждый из которых начинает с просмотра .

ОТРЕДАКТИРОВАНО 17 ноября 2021 г.

Как немного обсуждалось в комментариях, я подозреваю, что наиболее оптимальный путь — это использование нескольких запросов. Первый запрос просто выполняет на всех идентификаторах, которые вы потенциально собираетесь добавить. Пусть он вернет список найденных идентификаторов. Удалите те из набора, чтобы добавить. Затем разбейте добавляемую часть на партии и делайте это без как вы теперь знаете, что этих элементов не существует. Это, скорее всего, лучший способ уменьшить блокировку и избежать CME (исключений). Если кто-то еще не пытается добавить их параллельно, я думаю, что я бы выбрал именно этот подход.

Другие вопросы по тегам