如何在Gremlin TinkerPop中找到首个结果后终止Repeat遍历
Gremlin查询:找到最短路径后终止深层遍历
核心问题分析
你原查询中sack().is(within('level'))不生效的原因是:aggregate('level')是在repeat...until循环结束后才执行的,循环内部的until条件无法访问这个未被填充的集合,自然无法触发终止逻辑。
你的需求是获取所有到s1的最短路径(最小sack值对应的路径),并停止更长路径的遍历,同时保留动态过滤不可信用户的逻辑,以下是可行方案:
方案一:分两次查询(简单高效)
先获取最短路径对应的最小sack值,再基于这个值遍历并终止过长路径:
步骤1:获取最小层级(最短距离)
min_level = g.withSack(0).V().has("name", "v0"). repeat(outE("Trust", "Audit").sack(sum).by('distance').inV().simplePath()). until(has('name', 's1')). sack().min().next()
步骤2:遍历并只保留最短路径
g.withSack(0).V().has("name", "v0"). repeat(outE("Trust", "Audit").as("e").sack(sum).by('distance'). inV().simplePath(). choose(select("e").hasLabel("Trust"), choose(select("e").has("distance", gte(0)), aggregate('allow'), aggregate('distrust') ) ) ). until( has('name', 's1'). or(). sack().is(gte(min_level)). // 超过最短层级就终止遍历 or(). where(within('distrust')) ). has('name', 's1'). sack().is(eq(min_level)). // 只保留最短路径 path()
方案二:单查询实现(实时跟踪最小层级)
通过sideEffect在遍历过程中动态更新已找到的最小层级,无需分开两次查询:
g.withSack(0).V().has("name", "v0"). aggregate('min_level').by(constant(Integer.MAX_VALUE)). // 初始化最小层级为极大值 repeat(outE("Trust", "Audit").as("e").sack(sum).by('distance'). inV().simplePath(). choose(select("e").hasLabel("Trust"), choose(select("e").has("distance", gte(0)), aggregate('allow'), aggregate('distrust') ) ). sideEffect( // 找到目标节点时更新最小层级 has('name', 's1'). sack().as('current'). select('min_level').unfold(). choose(select('current').is(lte(unfold())), select('min_level').store(constant(Integer.MAX_VALUE)).by(select('current')) ) ) ). until( has('name', 's1'). or(). sack().is(gte(select('min_level').unfold())). // 当前层级超过已找到的最小值则终止 or(). where(within('distrust')) ). has('name', 's1'). sack().is(eq(select('min_level').unfold())). // 过滤出最短路径 path(). dedup()
结果验证
以上两种方案都能得到你期望的结果:
==>[v[0],e[13][0-Trust->4],v[4],e[17][4-Audit->10],v[10],2] ==>[v[0],e[14][0-Trust->6],v[6],e[19][6-Audit->10],v[10],2]
内容的提问来源于stack exchange,提问作者Carsten Keutmann
相关产品推荐
相关产品推荐

