В Гремлине, как найти и отсортировать все триады связанных вершин, которым принадлежит данная вершина? - PullRequest
2 голосов
/ 10 февраля 2020

Я создаю социальное приложение, в котором пользователи могут быть друзьями.

Для данного пользователя A я хочу найти все триады пользователей, такие что A -isFriends-> B AND B -isFriends-> C AND C -isFriends-> A.

Мой текущий подход заключается в следующем:

g.V(A).repeat(__.out('isFriends')).times(3).path().by(id).toList()

, а затем за пределами gremlin я отфильтровываю все объекты Path, где первый объект не совпадает с последним объектом. Я предпочел бы, чтобы gremlin сделал эту фильтрацию для меня, но я не уверен, как фильтровать на основе вывода path().

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

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

Я использую драйвер javascript -gremlin (v3.4.4) и делаю запросы к AWS Нептун, где нет лямбд.

Пожалуйста, дайте мне знать, если мой подход или понимание выключены.

Ответы [ 2 ]

2 голосов
/ 11 февраля 2020

Ниже приведен запрос для ответа на оба ваших вопроса. оптимизировано для запуска только с 2 прыжками:

g.V().hasLabel("A").as("A").both("isFriends").as("B").aggregate("friends")
.out("isFriends").as("C").where(within("friends"))
.project("triad","mutual")
  .by(select("A","B","C").by(label()))
  .by(select("B","C").select(values).unfold()
    .both("isFriends").where(within("friends"))
    .groupCount().by().unfold()
    .where(select(values).is(eq(2)))
    .select(keys).label().fold())
.order().by(select("mutual").count(local), desc)

Некоторые объяснения:

  • Найдите друзей и сохраните их как 'friends'.
  • Затем найдите своих друзей, которые находятся в пределах 'friends', таким образом, подружитесь с A (используйте out на этот раз, чтобы избежать дублирования).
  • Используйте project, чтобы сделать результат более подробным .
  • Выбор A, B и C для получения триады.

Теперь самое интересное - найти общих друзей по триаде:

  • Начните с B и C и найдите их друзей, которые также являются друзьями.
  • Считайте по группам тех друзей и отфильтруйте только тех, у кого есть число 2 (друзья с B и C).
  • Наконец, сортируйте результаты по количеству общих друзей.

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

    .select(keys).label().fold())
.order().by(select("mutual").count(local), desc)

с:

    .count())
.order().by(select("mutual"), desc)

Наконец, если вы хотите только триады (все еще отсортированные), вы можете удалить пр. oject:

g.V().hasLabel("A").as("A").both("isFriends").as("B").aggregate("friends")
.out("isFriends").as("C").where(within("friends"))
.order().by(
    select("B","C").select(values).unfold()
    .both("isFriends").where(within("friends"))
    .groupCount().by().unfold().where(select(values).is(eq(2)))    
    .count(), desc)
.select("A","B","C").by(label()).select(values)
2 голосов
/ 11 февраля 2020

Итак, я попытался создать примерный график для вашей проблемы: примерный график

Вы пытаетесь найти простой циклический c путь, и я думаю, что вы можете достичь этого с помощью:

g.V().hasLabel('A').as('a')
.both('isFriends').as('b')
.both('isFriends').as('c')
.where(both('isFriends').hasLabel('A'))
.select('a', 'b', 'c')

Примечание: триады симметричны c, поэтому каждая из них будет возвращаться дважды.

...