复杂Gremlin查询的调试方法
復雜Gremlin查詢的調試方法
摘要:
Gremlin是圖數據庫查詢使用最普遍的基礎查詢語言。Gremlin的圖靈完備性,使其能夠編寫非常復雜的查詢語句。對于復雜的問題,我們該如何編寫一個復雜的查詢?以及我們該如何理解已有的復雜查詢?本文帶你逐步抽絲剝繭,完成復雜查詢的調試。
1. Gremlin簡介
Gremlin是Apache TinkerPop 框架下的圖遍歷語言。Gremlin是一種函數式數據流語言,可以使得用戶使用簡潔的方式表述復雜的屬性圖(property graph)的遍歷或查詢。每個Gremlin遍歷由一系列步驟(可能存在嵌套)組成,每一步都在數據流(data stream)上執行一個原子操作。
Gremlin是一種用于描述屬性圖中行走的語言。圖形遍歷分兩個步驟進行。
1.1. 遍歷源(TraversalSource)
開始節點選擇(Start node selection)。所有遍歷都從數據庫中選擇一組節點開始,這些節點充當圖中行走的起點。
Gremlin中的遍歷是從TraversalSource開始的。 GraphTraversalSource提供了兩種遍歷方法。
- GraphTraversalSource.V(Object … ids):從圖形的頂點開始遍歷(如果未提供id,則為所有頂點)。
- GraphTraversalSource.E(Object … ids):從圖形的邊緣開始遍歷(如果未提供id,則為所有邊)。
1.2. 圖遍歷(GraphTraversal)
走圖(Walking the graph)。從上一步中選擇的節點開始,遍歷會沿著圖形的邊行進,以根據節點和邊的屬性和類型到達相鄰的節點。遍歷的最終目標是確定遍歷可以到達的所有節點。您可以將圖遍歷視為子圖描述,必須執行該子圖描述才能返回節點。
V()和E()的返回類型是GraphTraversal。 GraphTraversal維護許多返回GraphTraversal的方法。GraphTraversal支持功能組合。 GraphTraversal的每種方法都稱為一個步驟(step),并且每個步驟都以五種常規方式之一調制(modulates)前一步驟的結果。
GraphTraversal中幾乎每個步驟都從MapStep,FlatMapStep,FilterStep,SideEffectStep或BranchStep擴展得到。
- 舉例:找到makro認識的人
1.3. Gremlin是圖靈完備的(Turing Complete)
這也就時說任何復雜的問題,都可以用Gremlin描述。
下面就調試和編寫復雜的gremlin查詢,給出指導思路和方法論。
2. 復雜Gremlin查詢的調試
Gremlin的查詢都是由簡單的查詢組合成復雜的查詢。所以對于復雜Gremlin查詢可以分為以下三個步驟,并逐步迭代完成所有語句的驗證,此方法同樣適用編寫復雜的Gremlin查詢。
2.1. 迭代調試步驟
- 注:此方法參照Stephen Mallette gremlins-anatomy的分析邏輯和用例。
2.2. 用例
2.2.1. 圖結構
gremlin> graph = TinkerGraph.open() ==>tinkergraph[vertices:0 edges:0] gremlin> g = graph.traversal() ==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard] gremlin>g.addV().property('name','alice').as('a').addV().property('name','bobby').as('b').addV().property('name','cindy').as('c').addV().property('name','david').as('d').addV().property('name','eliza').as('e').addE('rates').from('a').to('b').property('tag','ruby').property('value',9).addE('rates').from('b').to('c').property('tag','ruby').property('value',8).addE('rates').from('c').to('d').property('tag','ruby').property('value',7).addE('rates').from('d').to('e').property('tag','ruby').property('value',6).addE('rates').from('e').to('a').property('tag','java').property('value',10).iterate() gremlin> graph ==>tinkergraph[vertices:5 edges:5]2.2.2. 查詢語句
gremlin>g.V().has('name','alice').as('v').repeat(outE().as('e').inV().as('v')).until(has('name','alice')).store('a').by('name').store('a').by(select(all, 'v').unfold().values('name').fold()).store('a').by(select(all, 'e').unfold().store('x').by(union(values('value'), select('x').count(local)).fold()).cap('x').store('a').by(unfold().limit(local, 1).fold()).unfold().sack(assign).by(constant(1d)).sack(div).by(union(constant(1d),tail(local, 1)).sum()).sack(mult).by(limit(local, 1)).sack().sum()).cap('a') ==>[alice,[alice,bobby,cindy,david,eliza,alice],[9,8,7,6,10],18.833333333333332]好長,好復雜!
看我如何抽絲剝繭,一步步驗證結果。
2.3. 調試過程
2.3.1. 拆分查詢
按執行步驟,拆分成小的查詢,如下圖:
- 執行第一部分步驟
2.3.2. 澄清結果
這里通過valueMap()輸出節點信息。
gremlin> g.V().has('name','alice').as('v'). ......1> repeat(outE().as('e').inV().as('v')). ......2> until(has('name','alice')).valueMap() ==>[name:[alice]]2.3.3. 驗證假設
根據執行語句的語義推導查詢過程,如下:
使用path(), 驗證推導過程
g.V().has('name','alice').as('v'). ......1> repeat(outE().as('e').inV().as('v')). ......2> until(has('name','alice')).path().next() ==>v[0] ==>e[10][0-rates->2] ==>v[2] ==>e[11][2-rates->4] ==>v[4] ==>e[12][4-rates->6] ==>v[6] ==>e[13][6-rates->8] ==>v[8] ==>e[14][8-rates->0] ==>v[0]- 輸出結果與推導結果一致,擴大查詢語句, 回到步驟1;
- 如不一致或不理解結果, 縮小步驟范圍, 可以采用此步驟的上一層查詢步驟,回到步驟1;
- 如此循環直到完全理解整個查詢。
大家可以自己去細細的剝下筍,此處略去3000字。
3. 總結
- 在分析的過程,采用劃分查詢語句的方法,分步理解,采用漏斗式的方法,逐步擴大對語句的理解;
- 對每步的查詢結果,可以采用利用valueMap(), path(), select(), as(), cap() 等函數輸出和驗證結果;
- 對于不清楚結果的步驟或與期望值不一致,縮小查詢步驟,可以采用輸出步驟的前一步驟作為輸出點,進行輸出和驗證;
- 對于上一層數據的結果明確的情況下,可以采用inject()方式注入上層輸出,繼續后續的輸出和驗證;
- 要注意步驟最后的函數,對整個輸出結果的影響。
4. 參考
- Introduction to Gremlin
- Gremlin’s Anatomy
- TinkerPop Documentation
- Stephen Mallette gremlins-anatomy
- Practical Gremlin - Why Graph?
總結
以上是生活随笔為你收集整理的复杂Gremlin查询的调试方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SCCM 2007 R2 setp by
- 下一篇: 【Qt Quick】配置vc2017环境