1. 程式人生 > >MapReduce實現基本SQL操作的原理-join和group by,以及Dinstinct

MapReduce實現基本SQL操作的原理-join和group by,以及Dinstinct

詳細講解SQL編譯為MapReduce之前,我們先來看看MapReduce框架實現SQL基本操作的原理

Join的實現原理

select u.name, o.orderid from order o join user u on o.uid = u.uid;

在map的輸出value中為不同表的資料打上tag標記,在reduce階段根據tag判斷資料來源。MapReduce的過程如下(這裡只是說明最基本的Join的實現,還有其他的實現方式)

MapReduce CommonJoin的實現

Group By的實現原理

select rank, isonline, count(*) from city group by rank, isonline;

將GroupBy的欄位組合為map的輸出key值,利用MapReduce的排序,在reduce階段儲存LastKey區分不同的key。MapReduce的過程如下(當然這裡只是說明Reduce端的非Hash聚合過程)

MapReduce Group By的實現

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即可完成去重

MapReduce Distinct的實現

如果有多個distinct欄位呢,如下面的SQL

select dealid, count(distinct uid), count(distinct date) from order group by dealid;

實現方式有兩種:

(1)如果仍然按照上面一個distinct欄位的方法,即下圖這種實現方式,無法跟據uid和date分別排序,也就無法通過LastKey去重,仍然需要在reduce階段在記憶體中通過Hash去重

MapReduce Multi Distinct的實現

(2)第二種實現方式,可以對所有的distinct欄位編號,每行資料生成n行資料,那麼相同欄位就會分別排序,這時只需要在reduce階段記錄LastKey即可去重。

這種實現方式很好的利用了MapReduce的排序,節省了reduce階段去重的記憶體消耗,但是缺點是增加了shuffle的資料量。

需要注意的是,在生成reduce value時,除第一個distinct欄位所在行需要保留value值,其餘distinct資料行value欄位均可為空。

MapReduce Multi Distinct的實現

SQL轉化為MapReduce的過程

瞭解了MapReduce實現SQL基本操作之後,我們來看看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任務的變換,生成最終的執行計劃

下面分別對這六個階段進行介紹