第19期 Gremlin Steps:
sack()
本系列文章的Gremlin示例均在HugeGraph圖數據庫上執行,環境搭建可參考準備Gremlin執行環境,本文示例均以其中的“TinkerPop關係圖”爲初始數據,如下圖所示:
結果存取口袋說明
Gremlin在路徑遊走的時候,可以將中間結果存放到一個叫口袋(sack)的結構裏面,以備在後續步驟中使用;此外在放入數據到口袋的時候,還可以做一些靈活的操作比如:分裂(split)、合併(merge)等。sack相關step屬於Gremlin語言裏面的高級操作,在處理較爲複雜的任務時可以靈活的實現一些特殊功能。
下面講解實現上述功能的具體Step:
withSack()
: 創建一個口袋,並給定一個初始結構,比如可以是一個返回Map或者隨機數的lambda函數,也可以是一個對象或常數;另外還可以提供lambda分裂函數,以指定當traverser分裂時的行爲,比如進行clone操作。sack()
: 將數據放入口袋,或者從口袋取出數據。當傳入lambda合併函數作爲參數時,可指定放入口袋的行爲如何執行;當不傳入參數時表示讀取口袋中的內容。
實例講解
下面通過實例來深入理解每一個操作。
-
Step
withSack()…sack()
: 利用口袋來存取結果示例1:
// 創建一個包含常數1的口袋, // 並且在最終取出口袋中的值 g.withSack(1).V().sack()
示例2:
// 創建一個包含常數1的口袋, // 並且在最終取出口袋中的值 g.withSack{new Random().nextFloat()} .V().sack()
試一試:將
g.withSack{}
的大括號換爲小括號g.withSack()
看看有什麼區別示例3:
// 通過sum求和的方式把數據放入口袋 g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV()) .times(3).sack()
試一試:通過以下gremlin查看路徑及其權重:
g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV()) .times(3).path().by().by('weight')
示例4:
// 通過lambda函數來指定放入口袋的行爲 // 注意:提供的初始值爲Map類型,而且 // 當traverser分裂時會拷貝Map g.withSack{[:]}{it.clone()} .V().out().out().dedup() .sack{m,v -> m[v.value('name')] = v.value('lang'); m} .sack()
試一試:去掉分裂函數後看看效果:
g.withSack{[:]} .V().out().out().dedup() .sack{m,v -> m[v.value('name')] = v.value('lang'); m} .sack()
示例5:
// 平均獲取口袋中的值 g.withSack(1.0).V('javeme') .out('knows').out('created') .barrier(normSack).sack()
綜合運用
-
獲取路徑並計算路徑權重之和
// 獲取路徑的同時通過sack(sum)計算權重之和 // 最終通過select把權重和路徑選取出來 g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV().as('p')) .times(3).sack().as('w') .select('w', 'p').by().by{p->p.toString()}.limit(3)
-
獲取路徑並根據路徑權重之和排序
// 獲取路徑的同時通過sack(sum)計算權重之和 // 最終通過order().by(sack())根據總權重排序 g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV()) .times(3).order().by(sack(),decr) .path().limit(3)
下一期:深入學習Gremlin(20):barrier