第22期 Gremlin Steps:
hasNext()
、next()
、tryNext()
、toList()
、toSet()
、toBulkSet()
、fill()
、iterate()
本系列文章的Gremlin示例均在HugeGraph圖數據庫上執行,環境搭建可參考準備Gremlin執行環境,本文示例均以其中的“TinkerPop關係圖”爲初始數據。
說明
Gremlin 中有一類特殊的操作,它能夠終止遍歷器的“遍歷”行爲,使其執行並返回結果。在這裏要強調的一點:原生的 Gremlin 語句通常都是用遍歷器連接起來的,但其實這些連接的過程並不會執行 Gremlin 語句,只有走到了terminal
Step 時纔會執行。這個模式類似於 Spark 中對RDD
的map
和action
操作。
hasNext
: 判斷遍歷器是否含有元素(結果),返回布爾值;next
: 不傳參數時獲取遍歷器的下一個元素,也可以傳入一個整數 n,則獲取後面 n 個元素;tryNext
:hasNext
和next
的結合版,返回一個Optional
對象,如果有結果還需要調用get()
方法才能拿到;toList
: 將所有的元素放到一個List
中返回;toSet
: 將所有的元素放到一個Set
中返回,會去除重複元素;toBulkSet
: 將所有的元素放到一個能排序的List
中返回,重複元素也會保留;fill
: 傳入一個集合對象,將所有的元素放入該集合並返回,其實toList
、toSet
和toBulkSet
就是通過fill
Step實現的;iterate
: 這個 Step 在終止操作裏面有點特殊,它並不完全符合終止操作的定義。它會在內部迭代完整個遍歷器但是不返回結果。
那肯定有細心的同學要問了,前面我們介紹了那麼多的 Step 很多都沒有加terminal
Step 啊,爲什麼也能返回結果呢?其實這是 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。