使用Gremlin查询指定起点关联顶点边 解决OrientDB循环遍历栈溢出问题
问题分析
- 原查询触发栈溢出的核心原因有两个:
- 双向遍历(
bothE/bothV)没有做路径去重,会反复在相邻顶点之间来回遍历形成死循环 - 多次嵌套
cap、aggregate和repeat操作,冗余计算量过大,重复遍历相同路径
- 双向遍历(
- 原需求是从指定顶点出发,遍历
contained和uses两类边,返回所有经过的顶点、边,以及叶子节点的全部边,不需要拆分多段遍历,单轮带去重的遍历即可完成需求
优化后的查询语句
g.V().has("name", "p1"). // 存储所有已经访问过的元素,避免重复遍历 store('visited'). repeat( // 遍历当前顶点的两类边,排除已经访问过的边 bothE("contained", "uses").where(without('visited')). store('visited'). // 取边的另一端顶点,排除已经访问过的顶点 otherV().where(without('visited')). store('visited') ). // 直到没有新的顶点/边可以遍历为止 until(not(bothE("contained", "uses").where(without('visited')))). // 最后取出所有存储的访问元素 cap('visited'). unfold(). limit(1000)
优化点说明
- 去掉了冗余的多轮
repeat和sideEffect嵌套,整段逻辑合并为单轮遍历,大幅降低计算量 - 用
store('visited')全程记录已经访问过的顶点和边,遍历时通过where(without('visited'))直接过滤已经走过的路径,从根源上避免循环 - 直接在
bothE里指定边标签,不需要额外加or判断,简化逻辑 - 用
otherV()替代bothV(),不需要额外判断当前顶点是边的起点还是终点,直接取对端顶点,避免重复返回当前顶点
如果需要输出和示例一致的顶点 边标签 对端顶点格式,可以使用以下调整后的查询:
g.V().has("name", "p1"). store('visited'). repeat( bothE("contained", "uses").where(without('visited')).as('e'). store('visited'). otherV().where(without('visited')).as('v'). // 遍历过程中直接格式化结果 select('e').project('out','label','in').by(outV().values('name')).by(label).by(inV().values('name')).store('result'). select('v'). store('visited') ). until(not(bothE("contained", "uses").where(without('visited')))). cap('result'). unfold()
内容的提问来源于stack exchange,提问作者Mhanna Abu Tareef
相关产品推荐
相关产品推荐

