CosmosDB Gremlin: использование сохраненного значения в последующем фильтре

У меня проблема при попытке фильтрации на основе сохраненного списка строк. Я хочу построить этот список в sideEffect() а затем использовать его в последующем where(without()), Я ожидаю список пользователей, исключая user.a1 в следующем примере, но user.a1 Включено.

g.V().hasLabel('user').sideEffect(hasId('user.a1').id().store('exclude')).where(id().is(without('exclude')))
[
    {
        "id": "user.a1",
        "label": "user",
        "type": "vertex"
    },
    {
        "id": "user.b1",
        "label": "user",
        "type": "vertex"
    },
    ...
]

Я предполагаю, что это происходит, потому что Гремлин проверяет литеральную строку excludeтак, как мне заставить это проверить идентификаторы, хранящиеся в exclude переменная вместо?

Например, это работает:

g.V().hasLabel('user').sideEffect(hasId('user.a1').id().store('exclude')).where(id().is(without('user.a1')))
[
    {
        "id": "user.b1",
        "label": "user",
        "type": "vertex"
    },
    ...
]

РЕДАКТИРОВАТЬ #1

Пробовал вопросы, предложенные stephen mallette, но все еще не получил именно то, что я ищу (может быть, это невозможно на CosmosDB?).

Прежде всего, по-видимому filter недоступна на CosmosDB:

g.V().hasLabel('user').
  sideEffect(hasId('user.a1').id().store('exclude')).
  filter(id().where(without('exclude')))

ExceptionType : GraphCompileException
ExceptionMessage : Gremlin Query Compilation
Error: Unable to find any method 'filter' @ line 1, column 81. 1
Error(s) Source : Microsoft.Azure.Graphs

Второе предложение привело к пустому набору, а второе сработало:

g.V().hasLabel('user').hasId('user.a1').
  aggregate('exclude').where(without('exclude'))
[]

g.V().hasLabel('user').
  sideEffect(hasId('user.a1').aggregate('exclude')).
  where(without('exclude'))
[
  {
    "id": "user.b1",
    "label": "user",
    "type": "vertex"
  },
  {
    "id": "user.b2",
    "label": "user",
    "type": "vertex"
  },
  ...
]

Проблема в том, что я хочу фильтровать ребра, используя значения их свойств. Моя реальная ситуация такова, что я хочу объединить следующие два запроса в один, если это возможно: получить набор role идентификаторы вершин, а затем получить пользователей, которые играют одну из ролей и принадлежат к подгруппе групп. (Пользователи принадлежат к группе с идентификатором роли в этой группе, установленным как свойство пользователя-> группа belongs_to край.)

  1. Получить набор ролей из иерархии ролей (role.2 + все родители)
g.V('role.2').store('roles').
  repeat(__.out('is_under')).emit().store('roles').
  select('roles').unfold().dedup().id()
[
    "role.2",
    "role.1"
]
  1. Получите пользователей с вышеуказанными ролями в группе B или выше и дайте им преимущество в другой роли.
g.V('group.B').
  sideEffect(inE('belongs_to').
    has('role',within('role.1','role.2')).outV().store('users')).
  repeat(__.out('belongs_to')).emit().inE('belongs_to').
    has('role',within('role.1','role.2')).outV().store('users').
  select('users').unfold().addE('has').to(g.V('role.12'))

1 ответ

Вот один из способов сделать это:

g.V().hasLabel('user').
  sideEffect(hasId('user.a1').id().store('exclude')).
  filter(id().where(without('exclude')))

Есть несколько вещей, которые вы можете изменить в зависимости от того, насколько этот пример, который вы создали, соответствует вашим реальным потребностям или был упрощен из-за вашего вопроса. Во-первых, вы можете, вероятно, отложить sideEffect() так как store() сам по себе является технически побочным эффектом. Во-вторых, интересно, если вы действительно хотите store() там нет aggregate() - где агрегат будет жадно собирать все идентификаторы, прежде чем перейти к фильтрации:

g.V().hasLabel('user').
  hasId('user.a1').aggregate('exclude').by(id).
  filter(id().where(without('exclude')))

Это, конечно, небольшой обход "ничего не делать", так как вы уже отфильтровали вершины, которые вам не нужны hasId('user.a1'), но, опять же, я предполагаю, что у вас есть более сложный запрос, чем тот, который вы продемонстрировали. Я просто указываю на механику Гремлин.

Вы также можете упростить дальнейшее упрощение, если не беспокоитесь об идентификаторах - равенство вершин будет таким же, как у идентификатора, и, следовательно, следующее будет эквивалентно приведенному выше с меньшим количеством шагов Gremlin:

g.V().hasLabel('user').
  hasId('user.a1').aggregate('exclude').
  where(without('exclude'))

Задавая вопросы о Gremlin, лучше всего добавить сценарий, который генерирует примеры данных, чтобы вы могли получить проверенный обход, соответствующий вашим потребностям. Вместо этого я изменил "современный" график, добавив метку "weight":

gremlin> g.addV('weight').property('v',1.0d)
==>v[13]

где значение "v" соответствует двум значениям веса для существующих ребер игрушечного графа. Без filter()Я думаю, что вы попадаете в такую ​​схему:

gremlin> g.V().hasLabel('weight').
......1>   aggregate('w').by('v').
......2>   V().hasLabel('person').
......3>   outE().as('x').values('weight').
......4>   where(within('w')).
......5>   select('x')
==>e[8][1-knows->4]
==>e[10][4-created->5]
Другие вопросы по тегам