深入學習Gremlin(22):遍歷終止terminal

第22期 Gremlin Steps:

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

本系列文章的Gremlin示例均在HugeGraph圖數據庫上執行,環境搭建可參考準備Gremlin執行環境,本文示例均以其中的“TinkerPop關係圖”爲初始數據。

tinkerpop關係圖

上一期:深入學習Gremlin(21):局部操作local

說明

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):轉換操作map/flatMap

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章