深入学习Gremlin(22):遍历终止操作

第22期 Gremlin Steps:

hasNext()next()tryNext()toList()toSet()toBulkSet()fill()iterate()

本系列文章的Gremlin示例均在HugeGraph图数据库上执行,环境搭建可参考准备Gremlin执行环境,本文示例均以其中的“TinkerPop关系图”为初始数据。

tinkerpop关系图

上一期:深入学习Gremlin(21):待添加

说明

Gremlin 中有一类特殊的操作,它能够终止遍历器的“遍历”行为,使其执行并返回结果。在这里要强调的一点:原生的 Gremlin 语句通常都是用遍历器连接起来的,但其实这些连接的过程并不会执行 Gremlin 语句,只有走到了terminalStep 时才会执行。这个模式类似于 Spark 中对RDDmapaction操作。

  • hasNext: 判断遍历器是否含有元素(结果),返回布尔值;
  • next: 不传参数时获取遍历器的下一个元素,也可以传入一个整数 n,则获取后面 n 个元素;
  • tryNext: hasNextnext的结合版,返回一个Optional对象,如果有结果还需要调用get()方法才能拿到;
  • toList: 将所有的元素放到一个List中返回;
  • toSet: 将所有的元素放到一个Set中返回,会去除重复元素;
  • toBulkSet: 将所有的元素放到一个能排序的List中返回,重复元素也会保留;
  • fill: 传入一个集合对象,将所有的元素放入该集合并返回,其实toListtoSettoBulkSet就是通过fillStep实现的;
  • iterate: 这个 Step 在终止操作里面有点特殊,它并不完全符合终止操作的定义。它会在内部迭代完整个遍历器但是不返回结果。

那肯定有细心的同学要问了,前面我们介绍了那么多的 Step 很多都没有加terminalStep 啊,为什么也能返回结果呢?其实这是 Tinkerpop 的 Gremlin 解析引擎对遍历器对象调用了一个IteratorUtils.asList()方法,又调用了它内部的fill()方法(注意:不是上面讲到的fill()Step)。

实例讲解

下面通过实例来深入理解每一个操作。

  1. Step hasNext()

    示例1:

    // 判断顶点“linary”是否包含“created”出顶点
    g.V('linary').out('created').hasNext()
    

    示例2:

    // 判断顶点“linary”是否包含“knows”出顶点
    g.V('linary').out('knows').hasNext()
    
  2. 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)。

  3. 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
    
  4. 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)有些类似。

  5. Step toSet()

    示例1:

    // 获取所有“person”顶点的“created”出顶点集合,放入Set中,不允许包含重复结果
    g.V().hasLabel('person').out('created').toSet()
    

    相比于toListtoSet去除了重复元素。

    示例2:

    // 获取所有“person”顶点的“created”入顶点集合,放入Set中,不允许包含重复结果
    g.V().hasLabel('person').in('created').toSet()
    
  6. Step toBulkSet()

    示例1:

    // 获取所有“person”顶点的“created”出顶点集合,放入BulkSet中,允许包含重复结果,排序
    g.V().hasLabel('person').out('created').toBulkSet()
    

    所谓的BulkSet虽然名字上带有"Set",但还是更像一个List,对比toList的结果,它实际上是把所有元素排了个序。

  7. Step fill()

    示例1:

    // 创建一个List,获取所有“person”顶点的“created”出顶点,并放入该List中
    results = []
    g.V().hasLabel('person').out('created').fill(results)
    results
    
  8. Step iterate()

    示例1:

    // 迭代所有“person”顶点
    it = g.V().hasLabel('person').iterate()
    it.hasNext()
    

    调用了iterate()后遍历器内部的元素就已经全部迭代过了,所以再调用hasNext()返回false。

下一期:深入学习Gremlin(23):待添加

你可能感兴趣的:(深入学习Gremlin(22):遍历终止操作)