遍历操作 #

一、遍历概述 #

1.1 什么是图遍历 #

图遍历是指从图中的一个或多个顶点出发,沿着边访问其他顶点的过程。

text
遍历类型:
├── 深度优先遍历(DFS)
├── 广度优先遍历(BFS)
├── 路径遍历
└── 模式匹配

1.2 遍历方向 #

text
遍历方向:
├── Out(出方向):从顶点沿出边遍历
├── In(入方向):从顶点沿入边遍历
└── Both(双向):两个方向都遍历

二、基本遍历 #

2.1 出边遍历 #

gremlin
// 遍历所有出边连接的顶点
g.V('1').out()

// 遍历指定标签的出边顶点
g.V('1').out('knows')

// 遍历多个标签的出边顶点
g.V('1').out('knows', 'follows')

// 获取出边
g.V('1').outE()

// 获取指定标签的出边
g.V('1').outE('knows')

// 从出边获取顶点
g.V('1').outE().inV()  // 等同于 g.V('1').out()

2.2 入边遍历 #

gremlin
// 遍历所有入边连接的顶点
g.V('1').in()

// 遍历指定标签的入边顶点
g.V('1').in('knows')

// 遍历多个标签的入边顶点
g.V('1').in('knows', 'follows')

// 获取入边
g.V('1').inE()

// 获取指定标签的入边
g.V('1').inE('knows')

// 从入边获取顶点
g.V('1').inE().outV()  // 等同于 g.V('1').in()

2.3 双向遍历 #

gremlin
// 遍历所有边连接的顶点
g.V('1').both()

// 遍历指定标签的双向顶点
g.V('1').both('knows')

// 获取所有边
g.V('1').bothE()

// 获取指定标签的所有边
g.V('1').bothE('knows')

2.4 遍历示例 #

gremlin
// Tom认识的人
g.V().has('name', 'Tom').out('knows').values('name')

// 认识Tom的人
g.V().has('name', 'Tom').in('knows').values('name')

// 与Tom有关系的人
g.V().has('name', 'Tom').both('knows').values('name')

三、多跳遍历 #

3.1 链式遍历 #

gremlin
// 两跳遍历
g.V('1').out('knows').out('knows')

// 三跳遍历
g.V('1').out('knows').out('knows').out('knows')

// 混合遍历
g.V('1').out('knows').in('knows')

3.2 repeat遍历 #

gremlin
// 重复N次
g.V('1').repeat(out('knows')).times(3)

// 直到条件
g.V('1').repeat(out('knows')).until(has('name', 'Jerry'))

// 发射所有中间结果
g.V('1').repeat(out('knows')).emit().times(3)

// 条件发射
g.V('1').repeat(out('knows')).emit(has('status', 'active')).times(3)

// emit在repeat前(包含起点)
g.V('1').emit().repeat(out('knows')).times(3)

3.3 until条件 #

gremlin
// 直到属性匹配
g.V('1').repeat(out()).until(has('name', 'Jerry'))

// 直到度数为0(叶子节点)
g.V('1').repeat(out()).until(outE().count().is(0))

// 直到深度限制
g.V('1').repeat(out()).until(loops().is(gt(5)))

// 组合条件
g.V('1').repeat(out()).until(
  or(
    has('name', 'Jerry'),
    loops().is(gt(5))
  )
)

3.4 loops() - 循环计数 #

gremlin
// 获取当前循环次数
g.V('1').repeat(out()).emit().times(5).as('v').
  project('vertex', 'depth').
    by('name').
    by(loops())

// 限制循环深度
g.V('1').repeat(out()).until(loops().is(gt(3)))

四、路径遍历 #

4.1 path() - 获取路径 #

gremlin
// 获取完整路径
g.V('1').out('knows').path()

// 路径属性
g.V('1').out('knows').path().by('name')

// 多跳路径
g.V('1').out('knows').out('knows').path().by('name')

// 带边的路径
g.V('1').outE('knows').inV().path()

4.2 simplePath() - 简单路径 #

gremlin
// 无环路径
g.V('1').repeat(out()).times(3).simplePath()

// 排除特定路径
g.V('1').out('knows').simplePath().where(without('1'))

4.3 cyclicPath() - 环路检测 #

gremlin
// 检测环路
g.V('1').repeat(out()).times(5).cyclicPath()

// 排除环路
g.V('1').repeat(out()).times(5).simplePath()

4.4 路径过滤 #

gremlin
// 路径长度过滤
g.V('1').out('knows').path().filter(count(local).is(eq(3)))

// 路径内容过滤
g.V('1').out('knows').path().filter(unfold().has('status', 'active'))

五、分支遍历 #

5.1 union() - 并集遍历 #

gremlin
// 合并多个遍历结果
g.V('1').union(
  out('knows'),
  out('follows')
).dedup()

// 合并不同方向
g.V('1').union(
  out('knows'),
  in('knows')
).dedup()

// 合并不同深度
g.V('1').union(
  out('knows'),
  out('knows').out('knows')
).dedup()

5.2 choose() - 条件遍历 #

gremlin
// if-else遍历
g.V().choose(
  has('type', 'person'),
  out('knows'),
  out('related')
)

// 多条件遍历
g.V().choose(has('status'))
  .option('active', out('knows'))
  .option('inactive', in('knows'))
  .option(none, both('knows'))

5.3 coalesce() - 首选遍历 #

gremlin
// 尝试多个遍历,返回第一个非空结果
g.V('1').coalesce(
  out('knows'),
  out('follows'),
  out('related')
)

// 带默认值
g.V('1').coalesce(
  out('knows'),
  constant([])  // 默认空列表
)

六、递归遍历 #

6.1 repeat递归 #

gremlin
// 递归遍历直到条件满足
g.V('1').repeat(out('parent')).until(has('name', 'Grandfather'))

// 递归遍历固定深度
g.V('1').repeat(out('parent')).times(3)

// 发射所有祖先
g.V('1').repeat(out('parent')).emit()

6.2 emit递归 #

gremlin
// 发射所有中间结果
g.V('1').emit().repeat(out('parent')).times(3)

// 条件发射
g.V('1').repeat(out('parent')).emit(has('gender', 'male'))

// 发射后继续遍历
g.V('1').emit().repeat(out('parent')).until(has('name', 'Grandfather'))

七、最短路径 #

7.1 BFS最短路径 #

gremlin
// 最短路径(广度优先)
g.V('1').repeat(out().simplePath()).until(hasId('2')).limit(1).path()

// 最短路径带属性
g.V().has('name', 'Tom').
  repeat(out().simplePath()).until(has('name', 'Jerry')).
  limit(1).
  path().by('name')

7.2 加权最短路径 #

gremlin
// 按权重计算最短路径
g.V('1').repeat(
  outE().sack(sum).by('weight').inV().simplePath()
).until(hasId('2')).
  limit(1).
  path().by('name').by('weight')

7.3 所有最短路径 #

gremlin
// 所有最短路径
g.V('1').repeat(out().simplePath()).until(hasId('2').or().loops().is(gt(5))).
  hasId('2').
  path()

// 限制路径数量
g.V('1').repeat(out().simplePath()).until(hasId('2')).limit(10).path()

八、子图遍历 #

8.1 subgraph() - 提取子图 #

gremlin
// 提取子图
g.V('1').repeat(outE().subgraph('subGraph').inV()).times(3).cap('subGraph')

// 提取路径子图
g.V('1').out('knows').outE().subgraph('edges').inV().cap('edges')

8.2 诱导子图 #

gremlin
// 获取顶点集的所有边
g.V().hasLabel('person').aggregate('vertices').
  bothE().where(bothV().where(within('vertices'))).aggregate('edges').
  cap('vertices', 'edges')

九、遍历优化 #

9.1 性能优化技巧 #

gremlin
// 使用标签过滤
g.V().hasLabel('person').out('knows')  // 好
g.V().out('knows')  // 慢

// 使用属性索引
g.V().has('userId', 'user_001').out('knows')  // 好

// 限制遍历深度
g.V('1').repeat(out()).times(3)  // 好
g.V('1').repeat(out()).until(...)  // 注意条件

// 使用limit
g.V('1').out('knows').limit(10)  // 好

// 避免重复计算
g.V().hasLabel('person').as('p').
  out('knows').as('f').
  select('p', 'f')  // 好

9.2 遍历策略 #

text
遍历策略:
├── 从小集合开始
├── 使用索引过滤
├── 限制遍历深度
├── 使用limit限制结果
└── 避免全图扫描

十、实际应用示例 #

10.1 社交网络遍历 #

gremlin
// 查找朋友的朋友
g.V().has('name', 'Tom').out('knows').out('knows').dedup()

// 查找共同好友
g.V().has('name', 'Tom').out('knows').
  where(out('knows').has('name', 'Jerry'))

// 查找N度人脉
g.V().has('name', 'Tom').repeat(out('knows')).times(3).dedup()

// 查找最短社交路径
g.V().has('name', 'Tom').
  repeat(out('knows').simplePath()).until(has('name', 'Jerry')).
  limit(1).path().by('name')

10.2 组织结构遍历 #

gremlin
// 查找所有下属
g.V().has('name', 'CEO').repeat(out('manages')).emit()

// 查找直属下属
g.V().has('name', 'CEO').out('manages')

// 查找上级链
g.V().has('name', 'Employee').repeat(in('manages')).emit()

// 查找同级同事
g.V().has('name', 'Tom').in('manages').out('manages').where(neq('Tom'))

10.3 知识图谱遍历 #

gremlin
// 查找相关概念
g.V().has('name', 'Graph Database').out('related').dedup()

// 查找概念层级
g.V().has('name', 'Graph Database').repeat(in('subClassOf')).emit()

// 查找实例
g.V().has('name', 'Database').repeat(out('subClassOf')).emit().out('instanceOf')

// 查找属性路径
g.V().has('name', 'Person').out('hasProperty').out('propertyType')

十一、总结 #

遍历操作要点:

操作 语法 说明
出边遍历 out() 沿出边遍历
入边遍历 in() 沿入边遍历
双向遍历 both() 双向遍历
重复遍历 repeat() 重复执行
路径遍历 path() 获取路径

最佳实践:

  1. 使用标签和属性过滤
  2. 限制遍历深度
  3. 使用limit限制结果
  4. 避免全图扫描
  5. 合理使用索引

下一步,让我们学习过滤与转换!

最后更新:2026-03-27