如何解决如何在 Gremlin 重复开始时执行一次关闭副作用?
我需要运行一个 Gremlin 查询,该查询从图的叶子(没有出边的顶点)和无边顶点沿着图向下移动,收集起始顶点和传入顶点(一次 1 级)直到一定的限度。不得超过此限制,因此如果下一级的入站顶点会导致计数超过限制,那么我们不会收集这些顶点并返回我们拥有的内容。这是我目前所拥有的:
g.V().or(__.not(outE()),__.not(bothE())).limit(700)
.store('a')
.repeat(__.sideEffect(select('b').store('a')).in().as('b'))
.until(union(cap('a').unfold().count(),select('b').count()).sum().is(gt(700)))
.cap('a').unfold()
问题在于 sideEffect
步骤中的 repeat
步骤对流中的每个顶点执行一次。无论流中有多少个顶点,我都希望它只执行一次。我该如何实现?
解决方法
我不确定这种方法是否适用于 CosmosDB,但它很可能是您可以实际使用 Gremlin 的唯一方法,它不涉及多个 Gremlin 请求和额外处理。我使用此示例图进行演示:
g = TinkerGraph.open().traversal()
g.addV().property(id,'A').as('a').
addV().property(id,'B').as('b').
addV().property(id,'C').as('c').
addV().property(id,'D').as('d').
addV().property(id,'E').as('e').
addV().property(id,'F').as('f').
addE('next').from('a').to('b').
addE('next').from('b').to('c').
addE('next').from('b').to('d').
addE('next').from('c').to('e').
addE('next').from('d').to('e').
addE('next').from('e').to('f').iterate()
该方法涉及使用 group()
,每次循环遍历 repeat()
时,您基本上都会形成一个新的遍历对象分组:
gremlin> g.V('A').
......1> group('m').by(constant(-1)).
......2> repeat(out().group('m').by(loops())).
......3> cap('m')
==>[-1:[v[A]],0:[v[B]],1:[v[C],v[D]],2:[v[E],v[E]],3:[v[F],v[F]]]
这为您提供了要处理的数据的结构,现在您只需要确保尽早终止 repeat()
:
gremlin> g.V('A').
......1> group('m').by(constant(-1)).
......2> until(cap('m').select(values).unfold().count(local).sum().is(gte(3))).
......3> repeat(out().group('m').by(loops())).
......4> cap('m')
==>[-1:[v[A]],v[D]]]
在上面的例子中,我们查看 until()
中的“m”,并对到目前为止收集的所有顶点进行计数。当它超过我们的最大值时,在这种情况下为“3”,我们退出。当我们退出时,我们可以看到我们收集的可能会或可能不会超出我们的需要。在这个例子中我们做到了,所以我们需要把它扔掉。从技术上讲,您需要除最后一组之外的所有分组来满足您的限制,但不幸的是,Gremlin 的“除最后一组”并不容易。我最终采用了这种方法,它基本上抓住了要扔掉的最后一项,然后将其用作对结果的过滤器。请注意,我们得到两个结果,因为遍历到下一个级别将超过我们总共“3”个结果的限制:
gremlin> g.V('A').
......1> group('m').by(constant(-1)).
......2> until(cap('m').select(values).unfold().count(local).sum().is(gt(3))).
......3> repeat(out().group('m').by(loops())).
......4> cap('m').
......5> select(values).as('v').
......6> tail(local).as('e').
......7> select('v').unfold().
......8> where(P.neq('e')).
......9> unfold()
==>v[A]
==>v[B]
请注意,当我们从“3”的限制增加到“4”时,结果会发生变化,因为遍历到下一个级别会将总数增加 2,但总数不会超过 4。
gremlin> g.V('A').
......1> group('m').by(constant(-1)).
......2> until(cap('m').select(values).unfold().count(local).sum().is(gt(4))).
......3> repeat(out().group('m').by(loops())).
......4> cap('m').
......5> select(values).as('v').
......6> tail(local).as('e').
......7> select('v').unfold().
......8> where(P.neq('e')).
......9> unfold()
==>v[A]
==>v[B]
==>v[C]
==>v[D]
下一个示例指出,我们不考虑重复项,因为从您的用例中不清楚预期的内容(或者这是否可行),但希望这为您提供了足够的结构,至少可以形成遍历您正在寻找:
gremlin> g.V('A').
......1> group('m').by(constant(-1)).
......2> until(cap('m').select(values).unfold().count(local).sum().is(gt(5))).
......3> repeat(out().group('m').by(loops())).
......4> cap('m').
......5> select(values).as('v').
......6> tail(local).as('e').
......7> select('v').unfold().
......8> where(P.neq('e')).
......9> unfold()
==>v[A]
==>v[B]
==>v[C]
==>v[D]
感谢 Kelvin Lawrence 建议我在这个答案中采用的一般方法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。