轉自 窩窩頭
我們學習hive的時候 都知道hive 是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射為一張表,並提供類SQL查詢功能 它的本質是:將HQL轉化成MapReduce程序
這篇文章就是從源碼角度看看 hive的底層是如何進行轉化的
為了能更好的理解源碼 需要先了解如下文字流程
SQL轉化為MapReduce任務的,整個編譯過程分為六個階段:
1.Antlr定義SQL的語法規則,完成SQL詞法,語法解析,將SQL轉化為抽象語法樹AST Tree
2.遍歷AST Tree,抽象出查詢的基本組成單元QueryBlock
3.遍歷QueryBlock,翻譯為執行操作樹OperatorTree
4.邏輯層優化器進行OperatorTree變換,合並不必要的ReduceSinkOperator,減少shuffle數據量
5.遍歷OperatorTree,翻譯為MapReduce任務
6.物理層優化器進行MapReduce任務的變換,生成最終的執行計划
接下來就開始看源碼 一點點找到上述流程對應的位置
首先CliDriver類是hive的入口 先看一下它的main方法
點進去 會發現一塊代碼專門處理 記錄歷史指令
記錄歷史指令的代碼下面 會看到一處while循環 不停的讀取命令執行
processLocalCmd 這個方法有4個主要流程
這樣就跟hive中查詢到的結果有了匹配 如下
既然數據都查出來 並且展示了 那么還是沒有看到是哪塊代碼進行轉化的
這里就需要看一下流程1的部分 里面包含了復雜的邏輯 下面一點點進行分析 底層是如何解析sql 然后一步步轉化Mapreduce 最后查詢結果的
而runInternal這個方法 又包含兩個步驟 一個是編譯 一個是執行
compile 里面包含三個步驟
第一個步驟點進去 會看到
這里是靠antlr 的解析器對sql語句轉化成 抽象語法樹 ASTNode 如果想對antlr有過多的了解 根據下面鏈接 自行了解 這里不深入說明
antlr :https://baike.baidu.com/item/antlr/9368750?fr=aladdin
第二個步驟點進去 會看到
analyzeInternal 這個方法設計的很有意思 它包含了11個步驟 並且作者每個步驟處都寫好了注釋 一個個分開說明 下面來看一下這11個小步驟都干了什么
這里可以了解一下 Operator:
Operator
Hive最終生成的MapReduce任務,Map階段和Reduce階段均由OperatorTree組成。邏輯操作符,就是在Map階段或者Reduce階段完成單一特定的操作。
基本的操作符包括TableScanOperator,SelectOperator,FilterOperator,JoinOperator,GroupByOperator,ReduceSinkOperator
從名字就能猜出各個操作符完成的功能,TableScanOperator從MapReduce框架的Map接口原始輸入表的數據,控制掃描表的數據行數,標記是從原表中取數據。JoinOperator完成Join操作。FilterOperator完成過濾操作
ReduceSinkOperator將Map端的字段組合序列化為Reduce Key/value, Partition Key,只可能出現在Map階段,同時也標志着Hive生成的MapReduce程序中Map階段的結束。
Operator在Map Reduce階段之間的數據傳遞都是一個流式的過程。每一個Operator對一行數據完成操作后之后將數據傳遞給childOperator計算。
Operator類的主要屬性和方法如下
RowSchema表示Operator的輸出字段
InputObjInspector outputObjInspector解析輸入和輸出字段
processOp接收父Operator傳遞的數據,forward將處理好的數據傳遞給子Operator處理
Hive每一行數據經過一個Operator處理之后,會對字段重新編號,colExprMap記錄每個表達式經過當前Operator處理前后的名稱對應關系,在下一個階段邏輯優化階段用來回溯字段名
由於Hive的MapReduce程序是一個動態的程序,即不確定一個MapReduce Job會進行什么運算,可能是Join,也可能是GroupBy,所以Operator將所有運行時需要的參數保存在OperatorDesc中,OperatorDesc在提交任務前序列化到HDFS上,在MapReduce任務執行前從HDFS讀取並反序列化。Map階段OperatorTree在HDFS上的位置在Job.getConf(“hive.exec.plan”) + “/map.xml”
總結 上面這11小個步驟 驗證了前面的文字流程
遍歷AST Tree,抽象出查詢的基本組成單元QueryBlock(步驟1)
遍歷QueryBlock,翻譯為執行操作樹OperatorTree(步驟2)
邏輯層優化器進行OperatorTree變換,合並不必要的ReduceSinkOperator,減少shuffle數據量(步驟7)
在這些步驟走完之后 compileInternal方法會生成一個執行計划 交給execute方法處理 接下來就看execute方法如何轉換MapReduce
有幾個點需要注意一下
下面基本就是轉換MapReduce的入口了 后面詳解
由此 基本可以了解HQl轉換MapReduce的整個流程 先是做一些判斷處理 然后處理sql 再切分遍歷執行每條sql 然后先通過antlr 根據語法文件 生成語法 詞法解析器 將sql解析成抽象語法樹 ASTNode 再將它解析成QB 然后翻譯成一個個的OperatorTree 接下來處理一下邏輯優化 最后生成執行計划 交給execute執行 它將task取出 放入隊列然后一個個提交任務 最后得出結果 打印ok 最后對返回數據的控制台打印處理。
整體流程說完了 接下來詳細說明一下 轉換MapReduce的入口
execute 這個方法很重要 根據task的類型不同 進行不同計算引擎的任務提交
先看一下MR
再看一下 Spark 我們都知道hive-on-Spark的說法 那么底層調用也是在這里
TezTask 不再贅述。
總結:hive的源碼還是值得去學習和思考的
前面通過不同的Task類型 進行可插拔的多計算引擎的選擇
不同的類型 不同的提交邏輯 提高程序的高擴展性。
最后附上完整流程圖