Повторно использовать результат Where Step в проекции - PullRequest
0 голосов
/ 06 марта 2020

Я получил примерный график, который можно построить с помощью следующего DSL:

g.addV('A').property(id, 'A1')
g.addV('B').property(id, 'B1').addE('B').from(V('A1'))
g.addV('B').property(id, 'B2').addE('B').from(V('A1'))
g.addV('C').property(id, 'C1').addE('C').from(V('B1'))
g.addV('C').property(id, 'C2').addE('C').from(V('B2'))
g.addV('BB').property(id, 'BB1').property('age', 2).addE('BB').from(V('B2'))
g.addV('BB').property(id, 'BB2').addE('BB').from(V('B2'))
g.addV('BB').property(id, 'BB3').addE('BB').from(V('B1'))

Я хочу пройтись по вершинам с меткой A, через ребра с меткой 'B', 'C' и вывести все пути с «BB», прикрепленными к каждой вершине «B», я могу получить результат, используя:

g.V().hasLabel('A').as('a').
out('B').as('b').
out('C').as('c').
project('shop', 'product', 'spec', 'device').
by(select('a').valueMap(true)).
by(select('b').valueMap(true)).
by(select('b').out('BB').valueMap(true).fold()).
by(select('c').valueMap(true))

Затем я столкнулся с другим сценарием, мне нужно отфильтровать вершину «B» с условие 'BB', которое может быть достигнуто с помощью:

g.V().hasLabel('A').as('a').
out('B').where(out('BB').has('age', 2)).as('b').
out('C').as('c').
project('shop', 'product', 'spec', 'device').
by(select('a').valueMap(true)).
by(select('b').valueMap(true)).
by(select('b').out('BB').has('age', 2).valueMap(true).fold()).
by(select('c').valueMap(true))

Мой вопрос: Могу ли я повторно использовать результат Where Step вместо фильтра 'BB' снова в Projection?

Любая помощь приветствуется.

1 Ответ

2 голосов
/ 06 марта 2020

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

Итак, в зависимости от Избирательность has('age',2) и тот факт, что where() на самом деле ищет только один результат, стоимость этого обхода не может быть ужасно дорогой, и вы могли бы с этим справиться дважды. Если это «дорого» и ваш граф поддерживает какой-то вершинно-центрированный c индекс, вы можете денормализовать «возраст» до края «ВВ», а затем просто сделать where(outE('BB').has('age',2)).

Другой способ, возможно, Посмотрите на это будет немного упростить ваш обход. Поскольку вы используете метки шагов, почему бы не исключить project() и напрямую обойти «BB»:

gremlin> g.V().hasLabel('A').as('shop').
......1>   out('B').as('product').
......2>   out('BB').has('age', 2).as('spec').
......3>   select('product').
......4>   out('C').as('device').
......5>   select('shop', 'product', 'spec', 'device').
......6>     by(valueMap(true))
==>[shop:[id:A1,label:A],product:[id:B2,label:B],spec:[id:BB1,label:BB,age:[2]],device:[id:C2,label:C]]

Это гораздо более читаемый обход, но он делает некоторые предположения о ваших данных и форме вашего результата, которые могут не совсем соответствует тому, что вы делали с project(). Я полагаю, что при достаточном количестве манипуляций с коллекцией Gremlin вы могли бы вернуть группировку вокруг «spe c» обратно, но тогда читаемость начинает разрушаться.

Следующий подход, кажется, жертвует некоторой читабельностью, чтобы выполнить out('BB').has('age',2) только один раз:

gremlin> g.V().hasLabel('A').as('shop').
......1>   out('B').as('product').
......2>   project('s').
......3>     by(out('BB').has('age', 2).valueMap(true).fold()).as('spec').
......4>   where(select('s').unfold()).
......5>   select('product').
......6>   out('C').as('device').
......7>   select('shop', 'product', 'spec', 'device').
......8>     by(valueMap(true)).
......9>     by(valueMap(true)).
.....10>     by(select('s')).
.....11>     by(valueMap(true)) 
==>[shop:[id:A1,label:A],product:[id:B2,label:B],spec:[[id:BB1,label:BB,age:[2]]],device:[id:C2,label:C]]

Если бы я смотрел на это в первый раз, я бы сразу задумался, в чем смысл строк 2-4. Не ясно, что весь смысл Map производства project('s') заключается в полной реализации результатов out('BB').has('age', 2), чтобы их можно было использовать в строке 4 для фильтрации этих траверсеров. Я не думаю, что мы часто рекомендуем этот подход, за исключением того, что в этом случае вам нужно реализовать весь результат, несмотря ни на что. Если есть хотя бы один результат, тогда вам нужны все из них, так что можете взять их всех сразу.

...