在投影中重复使用Where Step的结果



我得到了一个可以用以下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))

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

感谢您的帮助。

在您的方法的上下文中,不,您不能简单地在where()中重用遍历的结果。原因很简单,因为where()没有完全迭代结果——它寻求一个相当于hasNext()的值来检测Iterator中的第一个项。

因此,根据has('age',2)的选择性以及where()实际上只是在寻找一个结果的事实,遍历的成本可能不会非常昂贵,并且您可能会忍受它遍历两次。如果它是"昂贵的",并且你的图支持某种以顶点为中心的索引,你可以将"年龄"反规范化为"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行使用它们来过滤掉那些遍历器。我认为我们不会经常推荐这种方法,除非在这种情况下,无论发生什么,你都需要实现整个结果。如果只有一个结果,那么你需要所有的结果,所以不妨提前把它们都拿出来。

最新更新