使用Gremlin Sack跟踪已访问顶点的查询问题排查
问题描述
我希望利用Gremlin的sack来跟踪已遍历的顶点,当遍历器遇到已在列表中的顶点时停止继续遍历。sack可存储顶点本身、vertex id或name这类唯一属性。我以name为'TS'的顶点为起点,将其加入sack后尝试遍历两条边,确保到达的顶点不是起点,但返回的路径始终包含以TS起止的路径。我尝试了两段Gremlin查询代码:
第一段查询:
g.withSack([]){it.clone()} .V() .has('name', 'TS') .sack{a,v->a+=v.id()} .both() .both() .where(id().not(is(within(sack())))) .path().by('name')
第二段查询:
g.withSack([]){it.clone()} .V() .has('name', 'TS') .sack{a,v->a+=v.id()} .repeat( both() .where(id().not(is(within(sack())))) .sack{a,v->a+=v.id()} ) .times(2) .path().by('name')
注:我了解simplePath,但我的需求是仅跟踪部分已访问顶点(仅部分顶点会存入sack)。请问是我的查询有误,还是思路存在错误导致该方案不可行?
问题分析与解决方案
你的思路是可行的,问题出在查询的逻辑顺序和过滤时机上:
现有查询的问题
第一段查询:
在起点存入sack后,连续两次调用.both()时完全没有过滤逻辑——这意味着第一次跳转可能直接回到TS,第二次跳转也可能返回TS,最后才用.where()过滤顶点,此时包含TS的路径已经生成,自然会被返回。第二段查询:
虽然在repeat里加入了过滤,但逻辑顺序错误:先跳到顶点再判断是否在sack中,而且遍历器遇到已跟踪顶点时只是过滤掉当前顶点,不会提前终止整个分支的遍历。如果图结构存在回环,依然可能生成包含TS的路径。
修正后的查询
核心是提前过滤回已跟踪顶点的路径分支,在跳转前就判断目标顶点是否在sack中:
g.withSack([]){it.clone()} .V().has('name', 'TS') .sack{ a, v -> a << v.id() } // 初始化sack,存入起点ID .repeat( bothE() // 先获取边,避免直接跳到顶点 .where(otherV().id().not(within(sack()))) // 提前判断目标顶点不在sack中 .otherV() // 跳转到目标顶点 .sack{ a, v -> a << v.id() } // 将新顶点加入sack ).times(2) .path().by('name')
关键修改点
- 过滤时机前置:先通过
bothE()获取边,再用otherV()检查目标顶点是否在sack中,直接过滤掉会回到已跟踪顶点的路径分支,避免无效遍历。 - 列表更新方式:用
<<替代+=来添加元素,<<是原地修改列表,更符合sack的状态更新逻辑(+=会生成新列表,可能导致sack状态不同步)。 - 支持部分顶点跟踪:如果需要仅跟踪特定顶点,可在
sack更新步骤前添加过滤条件,比如只把标签为target的顶点存入sack:.sack{ a, v -> if(v.label() == 'target') a << v.id() else a }
内容的提问来源于stack exchange,提问作者ChristianSchmaler
相关产品推荐
相关产品推荐

