在投影中重用 Where Step 的结果

Reuse the result of Where Step in projection

我得到了一个示例图,可以使用以下 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' 的边,并输出每个 'B' 附加 'BB' 的所有路径顶点,我可以设法得到结果使用:

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))

然后我运行进入另一个场景,我必须过滤条件为'BB'的'B'个顶点,可以通过以下方式实现:

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))

我的问题是:我可以在 Projection 中再次使用 Where Step 的结果而不是过滤 'BB' 吗?

感谢任何帮助。

在您的方法的上下文中,不,您不能简单地在 where() 中重复使用遍历的结果。原因很简单,因为 where() 没有完全迭代结果 - 它寻求相当于 hasNext() 的内容来检测 Iterator.[=25= 中的第一项]

因此,根据 has('age',2) 的选择性以及 where() 实际上只是在寻找一个结果这一事实,该遍历的成本可能不会非常昂贵,您可能会接受它遍历两次。如果它是 "expensive" 并且您的图形支持某种以顶点为中心的索引,您可以将 "age" 非规范化为 "BB" 边,然后只执行 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 集合操作,您可以恢复 "spec" 周围的分组,但随后可读性开始崩溃。

以下方法似乎牺牲了一些可读性来执行 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 行的意义在哪里。目前尚不清楚 project('s') 生成的 Map 的全部意义在于完全实现 out('BB').has('age', 2) 的结果,以便可以在第 4 行使用它们来过滤掉那些遍历器。我认为我们不会经常推荐这种方法,除非在这种情况下无论如何您都需要实现整个结果。如果只有一个结果,那么你需要所有的结果,所以最好先把它们都拿下来。