Как выполнять эффективные массовые обновления (вставлять новую вершину или обновлять свойства) в Gremlin?

Контекст:

У меня есть граф примерно с 2000 вершинами и 6000 ребрами, со временем он может вырасти до 10000 вершин и 100000 ребер. В настоящее время я добавляю новые вершины, используя следующий запрос обхода:

Добавление вершин и краев

queryVertex = "g.V().has(label, name, foo).fold().coalesce(
               unfold(), addV(label).property(name, foo).property(model, 2)
               ).property(model, 2)"

Намерение здесь состоит в том, чтобы найти вершину с именем foo и, если она найдена, обновить ее свойство model, в противном случае создать новую вершину и установить свойство model. это выдается дважды: один раз для исходной вершины, а затем для целевой вершины.
После создания двух связанных вершин выдается другой запрос для создания ребра между ними:

queryEdge = "g.V('id_of_source_vertex').coalesce(
             outE(edge_label).filter(inV().hasId('id_of_target_vertex')), 
             addE(edge_label).to(V('id_of_target_vertex'))
             ).property(model, 2)"

здесь, если между двумя вершинами есть ребро, свойство model на ребре обновляется, в противном случае оно создает ребро между ними.

И псевдокод, который это делает, выглядит следующим образом:

for each edge in the list of new edges:
   //upsert source and target vertices:  
   execute queryVertex for edge.source
   execute queryVertex for edge.target
   // upsert edge: 
   execute queryEdge

Это работает, но крайне неэффективно; например, для указанного размера графика для завершения требуется несколько минут, а при некотором параллелизме внутри приложения это сокращает время всего на пару минут. Конечно, для такого маленького размера графа должен быть более эффективный способ сделать это.

Вопрос
* Как сделать эти апсерты быстрее?


person EasyQuestions    schedule 09.06.2020    source источник


Ответы (1)


Массовую загрузку обычно следует относить к инструментам конкретного поставщика, которые оптимизированы для обработки таких задач. Gremlin на самом деле не предоставляет абстракций для покрытия разнообразной группы инструментов массовой загрузки, которые существуют для каждой из различных систем графовых баз данных, реализующих TinkerPop. Для Нептуна, как вы пометили свой вопрос, это будет означать использование Навальный погрузчик Нептун.

Говоря конкретно о вашем вопросе, вы можете увидеть некоторые оптимизации того, что вы описали как свой подход. С точки зрения Gremlin, я полагаю, вы бы заметили здесь некоторую экономию, отправив один запрос Gremlin для каждого ребра, объединив существующие обходы:

g.V().has(label, name, foo).fold().
  coalesce(unfold(), 
           addV(label).property(name, foo)).
  property(model, 2).as('source').
  V().has(label, name, bar).fold().
  coalesce(unfold(), 
           addV(label).property(name, bar)).
  property(model, 2).as('target').
  coalesce(inE(edge_label).where(outV().as('source')), 
           addE(edge_label).from('source').to('target')).
  property(model, 2)

Думаю, я понял это правильно - непроверенный, но, надеюсь, вы поняли идею. По сути, мы просто ссылаемся на вершины, уже находящиеся в памяти, через метки шагов, так что нам не нужно запрашивать их повторно. Вы можете попробовать и другую тактику, если продолжите массовую загрузку в стиле Gremlin, например, упорядочите свои ребра, чтобы вы могли объединить больше нагрузок на ребра, чтобы уменьшить количество поисков вершин и отправлять данные вершин / ребер более динамичным образом, как описано здесь.

person stephen mallette    schedule 11.06.2020
comment
У меня был аналогичный вариант использования. Я хотел перевернуть большое количество вершин. Я тоже подумал о способе, который вы описали, но вместо этого получил 3 обхода: 1. Найти все вершины на основе (возможно, новых) идентификаторов. 2. Создайте вершины для всех не найденных идентификаторов. 3. Обновите все старые вершины. Это было НАМНОГО быстрее. Я использую JanusGraph tho, а не neptune. - person Nabil A.; 03.07.2020
comment
Я стараюсь отвечать на вопросы Гремлина таким образом, чтобы он отвечал непосредственно на исходный пост, но при этом предлагал предостережения и передовой опыт. Вполне возможно, что вы найдете более подходящие подходы, которые подходят для конкретных поставщиков графовых баз данных. Я предполагаю, что вы можете даже найти более быстрые подходы к массовой загрузке с помощью Spark, когда дело доходит до JanusGraph, в зависимости от ваших требований. - person stephen mallette; 04.07.2020