Следуйте определенному отношению (ребро с определенной меткой) между вершинами одного типа (вершинами с одной и той же меткой) в гремлине

Мне поручили написать запрос для внешнего приложения, визуализирующего базу данных Neptune Graph. Допустим, первая вершина - это элементы, а вторая вершина - пользователь. Пользователь может создать элемент. Существуют отношения между элементами для отображения элементов, полученных из другого элемента, например, в случае медиаклипов, вырезанных из исходного медиаклипа. Первый набор созданных элементов должен быть создан в вершине, такой как SERVER, по которой они сгруппированы в пользовательском интерфейсе.

Следующее требование:

Filtering on a vertex shows the full graph for that vertex:
(1) Follow all ITEM - ITEM relationships
(2) Show any ITEM - USER relationships up to 1 hop (i.e. further ITEMs linked to a USER not shown already by (1) should not be displayed)

Вот визуальное представление графика.

https://drive.google.com/file/d/1YNzh4wbzcdC0JeloMgD2C0oS6MYvfI4q/view?usp=sharing

Ниже приведен пример кода для воспроизведения этого графика. Этот график может стать еще глубже. Это просто простой пример. Пожалуйста, смотрите схему:

g.addV('SERVER').property(id, 'server1')
g.addV('SERVER').property(id, 'server2')
g.addV('ITEM').property(id, 'item1')
g.addV('ITEM').property(id, 'item2')
g.addV('ITEM').property(id, 'item3')
g.addV('ITEM').property(id, 'item4')
g.addV('USER').property(id, 'user1')


g.V('item1').addE('STORED IN').to(g.V('server1'))
g.V('item2').addE('STORED IN').to(g.V('server2'))
g.V('item2').addE('RELATED TO').to(g.V('item1'))
g.V('item3').addE('DERIVED FROM').to(g.V('item2') )
g.V('item3').addE('CREATED BY').to(g.V('user1'))

Результат должен быть в форме ниже, если это возможно:

[
 [
   {
     "V1": {},
     "E": {},
     "V2": {}
   }
 ]
]

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

g.V('${id}').as('V1').bothE().dedup().as('E')
    .otherV().hasLabel(within('USER','ITEM')).as('V2').path().limit(500).select('V1', 'E', 'V2').fold()

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

@stephen-mallette, я знаю, что ты эксперт в этом. Не могли бы вы помочь мне с этим, пожалуйста? Спасибо большое.

sage 23.07.2019 15:21

@daniel-kuppitz, пожалуйста, помогите с этим. Спасибо большое.

sage 23.07.2019 19:32

Я не совсем понимаю описание проблемы. Не могли бы вы предоставить небольшой образец графика?

Daniel Kuppitz 24.07.2019 04:57

@daniel-kuppitz, большое спасибо. Я отредактировал свой пост и добавил простое изображение графика. Вы можете увидеть это здесь drive.google.com/file/d/1YNzh4wbzcdC0JeloMgD2C0oS6MYvfI4q/…. Я буду рад, если вы можете помочь с запросом, чтобы пройти весь граф для всех ребер элемента -> элемента, показывая вершины, ребра и вершины назначения, а также свойства вершин таким образом, чтобы я мог получить данные для визуализировать график в интерфейсе. Спасибо большое.

sage 25.07.2019 01:46

Диаграммы — это хорошо, но код для создания примера графика был бы еще лучше. Например. как показано здесь: stackoverflow.com/questions/56922227/gremlin-find-highest-ma‌​tch Это определенно увеличивает время ответа, если люди, которые хотят ответить, не должны придумывать свой собственный образец графика, который соответствует вашей проблемной области. Кроме того, вы не указываете, какой формат вывода вы бы предпочли. Если это означает, что вы можете брать вершины и ребра в любом произвольном порядке, хорошо, в противном случае вы должны быть более конкретными.

Daniel Kuppitz 25.07.2019 06:52

@DanielKuppitz, теперь я добавил пример запроса и примеры результатов. Большое вам спасибо за вашу помощь. Мне очень жаль, что я не придумал код раньше.

sage 25.07.2019 08:18

@стефен-маллетт

sage 25.07.2019 08:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если я правильно понял все правила, то следующий запрос должен выдать желаемый результат:

g.V('${id}').aggregate('v1').
  repeat(__.as('V1').bothE().dedup().as('E').otherV().hasLabel('USER','ITEM').as('V2').
         aggregate('x').by(select('V1', 'E', 'V2'))).
    until(hasLabel('USER')).
  as('V1').bothE().dedup().as('E').otherV().hasLabel('ITEM').as('V2').
  aggregate('x').
    by(select('V1', 'E', 'V2')).
  cap('v1','x','v1').
  coalesce(select('x').unfold(),
           select('v1').unfold().project('V1'))

Выполненный на вашем примере графика, он дает:

gremlin> g.V('server1').aggregate('v1').
......1>   repeat(__.as('V1').bothE().dedup().as('E').otherV().hasLabel('USER','ITEM').as('V2').
......2>          aggregate('x').by(select('V1', 'E', 'V2'))).
......3>     until(hasLabel('USER')).
......4>   as('V1').bothE().dedup().as('E').otherV().hasLabel('ITEM').as('V2').
......5>   aggregate('x').
......6>     by(select('V1', 'E', 'V2')).
......7>   cap('v1','x','v1').
......8>   coalesce(select('x').unfold(),
......9>            select('v1').unfold().project('V1'))
==>[V1:v[server1],E:e[0][item1-STORED IN->server1],V2:v[item1]]
==>[V1:v[item1],E:e[2][item2-RELATED TO->item1],V2:v[item2]]
==>[V1:v[item2],E:e[3][item3-DERIVED FROM->item2],V2:v[item3]]
==>[V1:v[item3],E:e[4][item3-CREATED BY->user1],V2:v[user1]]
==>[V1:v[user1],E:e[4][item3-CREATED BY->user1],V2:v[item3]]

Спасибо большое. Я попробую это, но выполняет ли until(hasLabel('USER')) требование одного прыжка, в то время как остальная часть обхода продолжает следовать всем отношениям ITEM -> ITEM до конца графа?

sage 25.07.2019 09:36

Я где-то наткнулся на это условие, которое помогает пройти весь график - .until(outE().count().is(0))

sage 25.07.2019 09:37

Остальная часть обхода — это не repeat(), это просто еще один прыжок.

Daniel Kuppitz 25.07.2019 09:37

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

sage 25.07.2019 09:49

Я только что видел шаг dedup(), который вы добавили к краям. Большое спасибо. Это выглядит великолепно. Я отмечу это как ответ через некоторое время. Позвольте мне сделать несколько тестов.

sage 25.07.2019 10:11

Я заметил, что у последней записи есть дубликат, но если я заменю фильтр until(hasLabel('USER')) на until(bothE().count().is(0)), все будет уникальным. Знаете, почему это так? Однако сейчас я отмечу это как ответ. Мне может понадобиться ваша помощь для еще одного запроса, если у меня возникнут какие-либо проблемы, но это будет еще один вопрос SO. Большое спасибо за Вашу помощь.

sage 27.07.2019 15:20

Последний прыжок не контролируется repeat() и, следовательно, не имеет dedup()). Вы можете отфильтровать последние ребра по тому, что уже собрано в x. То, что until(bothE().count().is(0) заставляет это работать, больше похоже на совпадение.

Daniel Kuppitz 28.07.2019 19:13

Спасибо, Даниэль. Последний вопрос. Если я заменю until(hasLabel('USER')) на until(out().count().is(0)) для второго требования к одному прыжку, приведет ли это к обходу всего графа в этом случае?

sage 29.07.2019 00:34

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

Daniel Kuppitz 29.07.2019 08:20

Спасибо Даниэль. Вы случайно не видели вопрос, который я разместил на stackoverflow.com/questions/57245636/…? Если невозможно ограничить количество узлов, я не возражаю против ограничения количества записей. Спасибо.

sage 01.08.2019 06:04

Теперь я придумал решение, и мне нужен ваш обзор этого решения, прежде чем я отмечу его как ответ. Спасибо.

sage 01.08.2019 08:06

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