轉自:http://blog.csdn.net/sn_zzy/article/details/43446027
SQL轉化為MapReduce的過程
了解了MapReduce實現SQL基本操作之后,我們來看看Hive是如何將SQL轉化為MapReduce任務的,整個編譯過程分為六個階段:
- Antlr定義SQL的語法規則,完成SQL詞法,語法解析,將SQL轉化為抽象語法樹AST Tree
- 遍歷AST Tree,抽象出查詢的基本組成單元QueryBlock
- 遍歷QueryBlock,翻譯為執行操作樹OperatorTree
- 邏輯層優化器進行OperatorTree變換,合並不必要的ReduceSinkOperator,減少shuffle數據量
- 遍歷OperatorTree,翻譯為MapReduce任務
- 物理層優化器進行MapReduce任務的變換,生成最終的執行計划
Join的實現原理
select u.name, o.orderid from order o join user u on o.uid = u.uid;
在map的輸出value中為不同表的數據打上tag標記,在reduce階段根據tag判斷數據來源。MapReduce的過程如下(這里只是說明最基本的Join的實現,還有其他的實現方式)
Group By的實現原理
select rank, isonline, count(*) from city group by rank, isonline;
將GroupBy的字段組合為map的輸出key值,利用MapReduce的排序,在reduce階段保存LastKey區分不同的key。MapReduce的過程如下(當然這里只是說明Reduce端的非Hash聚合過程)
Distinct的實現原理
select dealid, count(distinct uid) num from order group by dealid;
當只有一個distinct字段時,如果不考慮Map階段的Hash GroupBy,只需要將GroupBy字段和Distinct字段組合為map輸出key,利用mapreduce的排序,同時將GroupBy字段作為reduce的key,在reduce階段保存LastKey即可完成去重
如果有多個distinct字段呢,如下面的SQL
select dealid, count(distinct uid), count(distinct date) from order group by dealid;
實現方式有兩種:
(1)如果仍然按照上面一個distinct字段的方法,即下圖這種實現方式,無法跟據uid和date分別排序,也就無法通過LastKey去重,仍然需要在reduce階段在內存中通過Hash去重
(2)第二種實現方式,可以對所有的distinct字段編號,每行數據生成n行數據,那么相同字段就會分別排序,這時只需要在reduce階段記錄LastKey即可去重。
這種實現方式很好的利用了MapReduce的排序,節省了reduce階段去重的內存消耗,但是缺點是增加了shuffle的數據量。
需要注意的是,在生成reduce value時,除第一個distinct字段所在行需要保留value值,其余distinct數據行value字段均可為空。