Gremlin遍历:如何实现仅跟随与首条遍历边时间范围重叠的边
核心问题原因
- 谓词引用逻辑错误:之前写的
has('To', gte('eFrom'))这类代码,会被Gremlin直接当成“边的To属性值大于等于字符串'eFrom'”来执行。时间戳类型和字符串类型永远不可能满足对比条件,不管之前用store存了多少值到eFrom集合里,这种写法都不会读取之前存储的上下文内容,所有边都会被过滤掉,最终返回空结果。 - 对比对象层级错位:之前写的
where(lte('firstEdge')).by('From'),实际执行逻辑是“取出当前边的From属性值,和标记为firstEdge的整个边对象做数值对比”,完全不是预期的“当前边的From值和首条边的From属性值对比”,匹配逻辑从根上就不成立。 - 区间重叠判断冗余:两个时间区间是否重叠有通用的充要判断逻辑,不需要嵌套多层or/and,只要把缺省的永久生效边的To值补成一个足够大的时间戳,就能统一对比逻辑。
修正后的实现逻辑
- 不使用全局store存易被遍历流程污染的全局集合,从第一步取出首条边的时间区间(From值、To值,无To属性则补为远大于业务最大时间的占位值代表永久生效),将这组固定值绑定为遍历上下文的
firstTimeRange,全程保持值不变。 - 后续循环遍历出边时,先对当前遍历到的边做同样的时间值补全,绑定为
currTimeRange。 - 用两个固定判断式做区间重叠校验:
- 当前边的From值 ≤ 首条边的To值
- 当前边的To值 ≥ 首条边的From值
满足这两个条件的边,时间区间一定和首条边有重叠,不需要额外的嵌套逻辑。
- 按照原有需求限制遍历深度、过滤目标顶点标签。
可运行的遍历代码
// 按实际业务的最大时间范围调整占位时间戳,代表永久生效的边的结束时间 def MAX_TS = 99999999999999L g.V('1').outE().as('firstEdge') // 固定绑定首条边的时间区间,补全缺省To值 .project('firstFrom', 'firstTo') .by(values('From')) .by(coalesce(values('To'), constant(MAX_TS))) .as('firstTimeRange') // 回到首条边指向的顶点开始循环遍历 .select('firstEdge').outV() .repeat( outE() // 补全当前边的时间值,缺省To用最大占位值 .project('currFrom', 'currTo') .by(values('From')) .by(coalesce(values('To'), constant(MAX_TS))) .as('currTimeRange') // 重叠判断 .where( select('currTimeRange').select('currFrom') .lte(select('firstTimeRange').select('firstTo')) ) .where( select('currTimeRange').select('currTo') .gte(select('firstTimeRange').select('firstFrom')) ) .select('currTimeRange') .inV() ) .emit() .times(2) .where(hasLabel('Person'))
补充说明
单独测试的短查询没有返回结果,本质不是store命令的问题——gte('eFrom')里的字符串'eFrom'会被当成固定对比字面值,不会关联到之前store存的内容,这种写法下所有边都通不过过滤,自然没有返回值。如果要正确引用之前存的上下文值,必须通过select()步骤把对应绑定值取出来,再传给谓词做对比。
内容的提问来源于stack exchange,提问作者bech
相关产品推荐
相关产品推荐

