7.循环操作
7.1、说明
循环操作是指多次执行某一部分语句,用于语句需要重复运行的场景,比如“查找朋友的朋友的朋友”,可以直接使用循环操作来完成即“查找3层朋友”,下面对具体的循环相关的Step进行说明:
- repeat()
: 指定要重复执行的语句,如
repeat(out(‘friend’)) - times()
: 指定要重复执行的次数,如执行3次
repeat(out(‘friend’)).times(3) - until(): 指定循环终止的条件,如一直找到某个名字的朋友为止
- repeat(out(‘friend’)).until(has(‘name’,‘xiaofang’))
- emit(): 指定循环语句的执行过程中收集数据的条件,每一步的结果只要符合条件则被收集,不指定条件时收集所有结果
- loops(): 当前循环的次数,可用于控制最大循环次数等,如最多执行3次
- repeat(out(‘friend’)).until(loops().is(3))
7.2、实例讲解
7.2.1、 repeat()
+ times()
:按照指定的次数重复执行语句
// 访问某个顶点的OUT邻接点(1次)
// 注意'okram'是顶点的id
g.V('okram').repeat(out()).times(1)
// 访问某个顶点的2度双向邻接点
// 访问第1个顶点的所有邻接点(第1层)
// 再访问第1层结果顶点的邻接点(第2层)
g.V('okram').repeat(both()).times(2)
// 访问某个顶点的3度OUT邻接点
// 访问第1个顶点的所有邻接点(第1层)
// 再访问第1层结果顶点的邻接点(第2层)
// 再访问第2层结果顶点的邻接点(第3层)
g.V('okram').repeat(out()).times(3)
7.2.2、 repeat()
+ until()
:根据条件来重复执行语句
// 查询顶点'okram'到顶点'Gremlin'之间的路径
// 循环的终止条件是遇到名称是'Gremlin'的顶点
g.V('okram')
.repeat(out())
.until(has('name', 'Gremlin'))
.path()
注意1:这里用到了path()来获取经过的路径,path的讲解请参考上一期。
注意2:until()与 times()是互斥的,两个语句无法同时存在于同一个循环中。
注意3:until()放在repeat()之前或之后的顺序是会影响逻辑的,放前面表示先判断再执行,放后面表示先执行后判断。请对比如下两个语句的执行结果:
g.V(‘okram’).repeat(out()).until(hasLabel(‘person’)).path()
g.V(‘okram’).until(hasLabel(‘person’)).repeat(out()).path()
7.2.3、 repeat()
+ emit()
:收集执行过程中的数据
// 查询顶点'okram'的所有OUT可达点的路径
g.V('okram')
.repeat(out())
.emit()
.path()
// 查询顶点'okram'的所有OUT可达点的路径
// 且必须满足是'person'类型的点
g.V('okram')
.repeat(out())
.emit(hasLabel('person'))
.path()
注意:emit()放在repeat()之前或之后的顺序是会影响结果的,放前面表示先收集再执行,放后面表示先执行后收集。请对比如下两个语句的执行结果:
g.V(‘okram’).repeat(out()).emit(hasLabel(‘person’)).path()
g.V(‘okram’).emit(hasLabel(‘person’)).repeat(out()).path()
// 查询顶点'okram'到顶点'Gremlin'之间的路径
// 此外还收集过程中的'person'类型的顶点
g.V('okram')
.repeat(out())
.until(has('name', 'Gremlin'))
.emit(hasLabel('person'))
.path()
注意:
emit()
与until()
搭配使用时,是“或”的关系而不是“与”的关系,满足两者间任意一个即可。
// 查询顶点'okram'的2度OUT可达点的路径
// 此外还收集'person'类型的顶点
g.V('okram')
.repeat(out()).times(2)
.emit(hasLabel('person'))
.path()
注意:
emit()
与times()
搭配使用时,是“或”的关系而不是“与”的关系,满足两者间任意一个即可。
7.2.4、 repeat()
+ loops()
:根据最大次数限制来重复执行语句
// 查询顶点'okram'的3度OUT可达点路径
g.V('okram')
.repeat(out())
.until(loops().is(3))
.path()
// 查询顶点'okram'到顶点'Gremlin'之间的路径
// 且之间只相差2跳的距离
// 其中的and()是指两个条件都满足
g.V('okram')
.repeat(out())
.until(has('name', 'Gremlin')
.and().loops().is(2))
.path()
7.3、综合运用
7.3.1、 查找子树
// 查找从一个节点出发,到
// 叶子节点结束的所有路径
// 这些路径的集合为一颗子树(子图)
g.V('okram')
.repeat(out())
.until(outE().count().is(0))
.path()
7.3.2、 查找两点之间的最短路径
// 已知两个顶点'okram'和'javeme',
// 通过任意关系来找到这两点之间的路径
// 且限制了最大深度为3
// 若存在那么第一条结果即是最短路径
g.V('okram')
.repeat(bothE().otherV().simplePath())
.until(hasId('javeme').and().loops().is(lte(3)))
.hasId('javeme')
.path()
注意:
bothE().otherV()
一般等价于both()
,但是在这里有一些差别,后者仅仅返回路径中的顶点信息,前者会把路径中的边信息也返回。