Гремлин: повторяйте до точки останова и объединяйте вершины вместе, чтобы получить значение - PullRequest
0 голосов
/ 15 апреля 2020

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

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

Я пробовал следующий запрос:

    g.V(userID)
     .repeat(
       repeat(out('sponsors')
         .until(somePredicate)
         .out('hasPoints')
         .as('level') // How do I know the current loop iteration so I can store level1/level2/level3 in as step dynamically?
         // This is where I'm stuck, since I have no idea how to capture and sum all the points in this subtree.
         .in('hasPoints')
     )
     .times(3)
     // Also need to output the point sums as a list/map here, e.g. ["level1": 100, "level2": 100],
     // "level1" being the first iteration of repeat and so on.

Любой указатель?

РЕДАКТИРОВАТЬ:

Вот сценарий Gremlin для примеров данных:

g.addV('user').property('id', 1).as('1')
  addV('user').property('id', 2).as('2').
  addV('user').property('id', 3).as('3').
  addV('user').property('id', 4).as('4').
  addV('user').property('id', 5).as('5').
  addV('user').property('id', 6).as('6').
  addV('user').property('id', 7).as('7').
  addV('point').property('value', 5).as('p1')
  addV('point').property('value', 5).as('p2').
  addV('point').property('value', 5).as('p3').
  addV('point').property('value', 5).as('p4').
  addV('point').property('value', 5).as('p5').
  addV('point').property('value', 5).as('p6').
  addV('point').property('value', 5).as('p7').
  addE('sponsors').from('1').to('2').
  addE('sponsors').from('1').to('3').
  addE('sponsors').from('1').to('4').
  addE('sponsors').from('2').to('5').
  addE('sponsors').from('3').to('6').
  addE('sponsors').from('4').to('7').
  addE('hasPoints').from('1').to('p1').
  addE('hasPoints').from('2').to('p2').
  addE('hasPoints').from('3').to('p3').
  addE('hasPoints').from('4').to('p4').
  addE('hasPoints').from('5').to('p5').
  addE('hasPoints').from('6').to('p6').
  addE('hasPoints').from('7').to('p7').
  iterate()

Это запрос, который я пишу для группировки уровней вместе на основе некоторого предиката:

g.V()
    .has('id', 1)
    .repeat('x',
        identity()
            .repeat(
                out('sponsors')
                    .choose(loops('x'))
                    .option(0, identity().as('a1'))
                    .option(1, identity().as('a2'))
                    .option(2, identity().as('a3'))
            )
            .until(or(out('hasPoints').has('value', gte(5))))
            .sideEffect(
                choose(loops('x'))
                    .option(0, select(all, 'a1'))
                    .option(1, select(all, 'a2'))
                    .option(2, select(all, 'a3'))
                    .unfold()
                    .choose(loops('x'))
                    .option(0, store('b1'))
                    .option(1, store('b2'))
                    .option(2, store('b3'))
            )
    )
    .times(3)
    .cap('b1', 'b2', 'b3')

Несмотря на то, что я могу вручную установить переменные и выбрать правильные переменные, я пока не знаю, как это сделать динамически - т. Е. Вместо times(3) может возникнуть ситуация, когда мне нужно, чтобы она была until , поэтому счетчик итераций больше не известен eforehand.

1 Ответ

1 голос
/ 16 апреля 2020

Я немного изменил ваши данные, добавив в них одно значение "point" меньше 5, чтобы доказать, что они фильтруются правильно, и изменил свойство "id" на T.id, чтобы результаты легче было читать во время тестирования. вещи:

g.addV('user').property(id, 1).as('1').
  addV('user').property(id, 2).as('2').
  addV('user').property(id, 3).as('3').
  addV('user').property(id, 4).as('4').
  addV('user').property(id, 5).as('5').
  addV('user').property(id, 6).as('6').
  addV('user').property(id, 7).as('7').
  addV('point').property('value', 5).as('p1').
  addV('point').property('value', 5).as('p2').
  addV('point').property('value', 5).as('p3').
  addV('point').property('value', 5).as('p4').
  addV('point').property('value', 5).as('p5').
  addV('point').property('value', 4).as('p6').
  addV('point').property('value', 5).as('p7').
  addE('sponsors').from('1').to('2').
  addE('sponsors').from('1').to('3').
  addE('sponsors').from('1').to('4').
  addE('sponsors').from('2').to('5').
  addE('sponsors').from('3').to('6').
  addE('sponsors').from('4').to('7').
  addE('hasPoints').from('1').to('p1').
  addE('hasPoints').from('2').to('p2').
  addE('hasPoints').from('3').to('p3').
  addE('hasPoints').from('4').to('p4').
  addE('hasPoints').from('5').to('p5').
  addE('hasPoints').from('6').to('p6').
  addE('hasPoints').from('7').to('p7').
  iterate()

Если вам просто нужно сгруппировать динамически на основе уровня, повторяемого repeat(), тогда вы можете просто group() на loops():

gremlin> g.V(1).
......1>   repeat(out('sponsors').
......2>          group('m').
......3>            by(loops()).
......4>            by(out('hasPoints').has('value',gte(5)).
......5>               values('value').sum())).
......6>   cap('m')
==>[0:15,1:10]

Вы упомянули что вы хотите, чтобы эти значения суммировались, что вы можете сделать достаточно легко:

gremlin> g.V(1).
......1>   repeat(out('sponsors').
......2>          group('m').
......3>            by(loops()).
......4>            by(out('hasPoints').has('value',gte(5)).
......5>               values('value').sum())).
......6>   cap('m').
......7>   unfold().
......8>   select(values).
......9>   sum()
==>25

Конечно, если вам просто нужна сумма, вы можете избежать group() полностью:

gremlin> g.V(1).
......1>   repeat(out('sponsors').
......2>          store('m').
......3>            by(coalesce(out('hasPoints').has('value',gte(5)).values('value'), 
......4>                        constant(0)))).
......5>   cap('m').
......6>   sum(local)
==>25

Наконец, если мы больше не заботимся об уровнях, тогда мы, вероятно, можем go лучше, избавиться от побочного эффекта "m" и сохранить эти накладные расходы:

gremlin> g.V(1).
......1>   repeat(out('sponsors')).
......2>     emit().
......3>   out('hasPoints').has('value',gte(5)).
......4>   values('value'). 
......5>   sum()
==>25
...