第22期 Gremlin Steps:
hasNext()、next()、tryNext()、toList()、toSet()、toBulkSet()、fill()、iterate()
本系列文章的Gremlin示例均在HugeGraph图数据库上执行,环境搭建可参考准备Gremlin执行环境,本文示例均以其中的“TinkerPop关系图”为初始数据。

说明
Gremlin 中有一类特殊的操作,它能够终止遍历器的“遍历”行为,使其执行并返回结果。在这里要强调的一点:原生的 Gremlin 语句通常都是用遍历器连接起来的,但其实这些连接的过程并不会执行 Gremlin 语句,只有走到了terminalStep 时才会执行。这个模式类似于 Spark 中对RDD的map和action操作。
-
hasNext: 判断遍历器是否含有元素(结果),返回布尔值; -
next: 不传参数时获取遍历器的下一个元素,也可以传入一个整数 n,则获取后面 n 个元素; -
tryNext:hasNext和next的结合版,返回一个Optional对象,如果有结果还需要调用get()方法才能拿到; -
toList: 将所有的元素放到一个List中返回; -
toSet: 将所有的元素放到一个Set中返回,会去除重复元素; -
toBulkSet: 将所有的元素放到一个能排序的List中返回,重复元素也会保留; -
fill: 传入一个集合对象,将所有的元素放入该集合并返回,其实toList、toSet和toBulkSet就是通过fillStep实现的; -
iterate: 这个 Step 在终止操作里面有点特殊,它并不完全符合终止操作的定义。它会在内部迭代完整个遍历器但是不返回结果。
那肯定有细心的同学要问了,前面我们介绍了那么多的 Step 很多都没有加terminalStep 啊,为什么也能返回结果呢?其实这是 Tinkerpop 的 Gremlin 解析引擎对遍历器对象调用了一个IteratorUtils.asList()方法,又调用了它内部的fill()方法(注意:不是上面讲到的fill()Step)。
实例讲解
下面通过实例来深入理解每一个操作。
-
Step
hasNext()示例1:
// 判断顶点“linary”是否包含“created”出顶点 g.V('linary').out('created').hasNext()示例2:
// 判断顶点“linary”是否包含“knows”出顶点 g.V('linary').out('knows').hasNext() -
Step
next()示例1:
// 获取顶点“javeme”的“knows”出顶点集合的下一个(第1个) g.V('javeme').out('knows').next()g.V('javeme').out('knows')返回的是一个遍历器(迭代器),每次执行这句话实际上都是获取的迭代器的第一个元素,那如果想获取第二个元素该怎么写呢?很简单,执行两次next()即可,但是这里的前提条件是遍历器中确实存在多个元素。示例2:
// 获取顶点“javeme”的“knows”出顶点集合的下一个(第2个) it = g.V('javeme').out('knows') it.next() it.next()示例3:
// 获取顶点“javeme”的“knows”出顶点集合的前两个 g.V('javeme').out('knows').next(2)next()与next(n)使用中有一点小小的区别,就是当没有元素或者没有足够多的元素时,执行next()会报错,但是执行next(n)则是返回一个空集合(List)。 -
Step
tryNext()示例1:
// 试图获取顶点“javeme”的“created”出顶点集合中的下一个 g.V('javeme').out('created').tryNext()这里细心的读者会发现结果与前面概述中说的有些不同。概述中说的是返回一个
Optional对象,要获取Optional对象里的值是需要调用它的get()方法的,怎么这里直接就把值给返回了呢?大家先别着急,我们再看一个例子。示例2:
// 试图获取顶点“javeme”的“created”入顶点集合中的下一个 g.V('javeme').in('created').tryNext()这里更加令人费解,没有“created”入顶点时竟然直接报错了,其实这是
HugeGraph的实现中关于Optional的序列化所致。HugeGraph序列化Optional对象时会判断该对象内的值是否存在,如果存在则取出来序列化该值,否则填入一个null。详细代码见HugeGraphSONModule.java中关于OptionalSerializer的实现。本文的重点在于学习
Gremlin语法本身,下面给出上述两个示例的预期结果:Optional[v[3:HugeGraph]] Optional.empty -
Step
toList()示例1:
// 获取所有“person”顶点的“created”出顶点集合,放入List中,允许包含重复结果 g.V().hasLabel('person').out('created').toList()示例2:
// 获取所有“person”顶点的“created”入顶点集合,放入List中,允许包含重复结果 g.V().hasLabel('person').in('created').toList()结果与
next(n)有些类似。 -
Step
toSet()示例1:
// 获取所有“person”顶点的“created”出顶点集合,放入Set中,不允许包含重复结果 g.V().hasLabel('person').out('created').toSet()相比于
toList,toSet去除了重复元素。示例2:
// 获取所有“person”顶点的“created”入顶点集合,放入Set中,不允许包含重复结果 g.V().hasLabel('person').in('created').toSet() -
Step
toBulkSet()示例1:
// 获取所有“person”顶点的“created”出顶点集合,放入BulkSet中,允许包含重复结果,排序 g.V().hasLabel('person').out('created').toBulkSet()所谓的
BulkSet虽然名字上带有"Set",但还是更像一个List,对比toList的结果,它实际上是把所有元素排了个序。 -
Step
fill()示例1:
// 创建一个List,获取所有“person”顶点的“created”出顶点,并放入该List中 results = [] g.V().hasLabel('person').out('created').fill(results) results -
Step
iterate()示例1:
// 迭代所有“person”顶点 it = g.V().hasLabel('person').iterate() it.hasNext()调用了
iterate()后遍历器内部的元素就已经全部迭代过了,所以再调用hasNext()返回false。














