ArangoDB - совокупная сумма дочерних атрибутов в DAG

У меня есть ведомость материалов, представленная в ArangoDB в виде ориентированного ациклического графа. Количество каждой детали в спецификации представлено на краях, в то время как названия деталей представлены ключами узлов. Я хотел бы написать запрос, который проходит вниз по DAG от узла-предка и суммирует количества каждой части по ее имени. Например, рассмотрим следующий график:

       Qty: 2          Qty: 1         
Widget +------> Gadget +------> Stuff 
    +               +  Qty: 4         
    |  Qty: 1       +---------> Thing 
    +----------------------------^    

Widget содержит два Gadgets, каждый из которых содержит один Stuff и четыре Things. Widget также содержит один Thing. Таким образом, я хотел бы написать запрос AQL, который пересекает граф, начиная с виджета, и возвращает:

{
  "Gadget": 2,
  "Stuff": 2,
  "Thing": 9
}

Я полагаю, что collect aggregate может быть здесь моим другом, но я еще не нашел нужного заклинания. Отчасти проблема заключается в том, что все дочерние количества детали необходимо умножить на их родительские количества. Как мог бы выглядеть такой запрос, который эффективно выполняет это суммирование для групп DAG глубиной около 10 уровней?


person Nate Gardner    schedule 05.12.2018    source источник


Ответы (1)


На ум приходят три возможных варианта:

1.- вернуть значения из пути, а затем суммировать данные на сервере приложения:

FOR v,e,p IN 1..2 OUTBOUND 'test/4719491' 
testRel
RETURN {v:v.name, p:p.edges[*].qty}

Это возвращает Gadget 2, Stuff [2,1], Thing [2,4], Thing [1].

2.- перечислить края на пути, чтобы получить результаты напрямую:

FOR v,e,p IN 1..2 OUTBOUND 'test/4719491' 
testRel
   let e0 = p.edges[0].qty
   let e1 = NOT_NULL(p.edges[1].qty,1)
   collect itemName = v.name aggregate items = sum(e0 * e1)
Return {itemName: itemName, items: items}

Это правильно возвращает Гаджет 2, Материал 2, Вещь 9.

Это, очевидно, требует, чтобы вы заранее знали количество уровней.

3.- Напишите пользовательскую функцию «умножение», аналогичную существующей функции «СУММ», чтобы вы могли умножать значения массива. Запрос будет примерно таким:

let vals = (FOR v,e,p IN 1..2 OUTBOUND 'test/4719491' 
            testRel
            RETURN {itemName:v.name, items:SUM(p.edges[*].qty)})
for val in vals
    collect itemName = val.itemName Aggregate items = sum(val.items)
return {itemName: itemName, items: items}

Таким образом, ваша функция заменит СУММ во внутреннем подвыборе. Здесь находится документация по пользовательским функциям.

person camba1    schedule 05.12.2018