Hive SQL 語義分析:select count(*) from tableName

從客戶端提交一個 Hive SQL  到 Driver 提交 MapReduce Job,有一個對SQL進行詞法分析和語義分析的過程,下面以 select count(*) from tableName 來描述其過程。

一、詞法分析

使用ANTLR分析SQL,生成語法樹,每個節點是一個 ASTNode,它有自己的類型。

來看看 select count(*) from tableName 的語法樹:

(
TOK_QUERY 
	(
	TOK_FROM 
		(
		TOK_TABREF 
			(
			TOK_TABNAME 
				   tt2
			)
		)
	) 
	(
	TOK_INSERT 
		(
		TOK_DESTINATION 
			(
			TOK_DIR 
				TOK_TMP_FILE
			)
		) 
		(
		TOK_SELECT 
			(
			TOK_SELEXPR 
				(
				TOK_FUNCTIONSTAR 
						 count
				)
			)
		)
	)
)


上面語法樹中,除括號外,每行對應一個 ASTNode,共13個節點,相互構成父子關係。

如:TOK_QUERY和TOK_INSERT爲TOK_FROM的子節點;tt2爲TOK_TABNAME的子節點。


二、語義分析

首先根據SQL類型創建對應的SemanticAnalyzer,對於這個sql,創建的就是 SemanticAnalyzer

1.分析語法樹的每個節點,將後面要用到的相關數據保存到 Query Block 

2.查詢表的元數據信息,順便做些檢查,如檢查 table 是否 offline

3.創建 Operator

4.優化

5.生成 Task

這些步驟中,除去輔助工作外,最重要的是3、5部分。


3 根據語法樹創建Operator

生成的 Operator 是個 DAG,每個節點是一個 Operator,每個 Operator 應該有指向所有子 Operator的指針,那麼Operator的數據結構至少是這個樣子:

class Operator<T extends OperatorDesc> implements Node {
  public List<Operator<? extends OperatorDesc>> getParentOperators() {
    return parentOperators;
  }
 public List<Operator<? extends OperatorDesc>> getChildOperators() {
    return childOperators;
  }
}
先看看 select count(*) from tableName 的Operator:

 
爲了生成  operator tree,首先創建 operator tree 的 root operator,而root operator 總是 TableScanOperator

這個步驟會爲所有from字句中的表創建一個 TableScanOperator,將 TableScanOperator 和表名的對應關係保存起來。

最先創建的總是 TableScanOperator,以後每創建一個Operator 都將當前Operator作爲它的父Operator

ReduceSinkOperator和它的子Operator: GroupByOperator是同時創建的,它來幫助mapper輸出結果,接着就由Reduce進行聚集操作。

所以創建Task時,如遇到處理的節點爲ReduceSinkOperator,就直接根據它的子Operator 來生成Reduce Task.

可見這個SQL 中 TableScanOperator 的子Operator 只有一個 SelectOperator;FileSinkOperator  有一個父Operator: SelectOperator

在explain 中就可查看有哪些Operator:

STAGE DEPENDENCIES:
  Stage-1 is a root stage
  Stage-0 is a root stage


STAGE PLANS:
  Stage: Stage-1
    Map Reduce
      Alias -> Map Operator Tree:
        tt2 
          TableScan    //[1]
            alias: tt2
            Select Operator   //[2]
              Group By Operator   //[3]
                aggregations:
                      expr: count()
                bucketGroup: false
                mode: hash
                outputColumnNames: _col0
                Reduce Output Operator    //[4]
                  sort order: 
                  tag: -1
                  value expressions:
                        expr: _col0
                        type: bigint
      Reduce Operator Tree:
        Group By Operator   //[5]
          aggregations:
                expr: count(VALUE._col0)
          bucketGroup: false
          mode: mergepartial
          outputColumnNames: _col0
          Select Operator   //[6]
            expressions:
                  expr: _col0
                  type: bigint
            outputColumnNames: _col0
            File Output Operator   //[7]
              compressed: false
              GlobalTableId: 0
              table:
                  input format: org.apache.hadoop.mapred.TextInputFormat
                  output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat


  Stage: Stage-0
    Fetch Operator
      limit: -1


上面 explain 中的Operator 已標出。
TableScanOperator 不用說了,望文生義吧

SelectOperator 可進行列修剪,可減少 mapper  的輸出數據量。

GroupByOperator 進行聚集操作,map 端的自然只能做部分聚集了。

FileSinkOperator 向文件系統寫SQL結果文件。


5根據 Operator tree 創建 Task

首先創建一個Dispatcher,它保存了用RegExp標識的規則和相應的節點處理器NodeProcessor的映射集合,

這個集合決定了每一個節點 Operator的命運,它決定了處理它的NodeProcessor.

不同的規則的正則表達式可匹配對應的 Operator。

然後頂端(TableScanOperator)開始遍歷這個DAG,爲每個節點(Operator)找出一個規則 Rule。


TableScanOperator 最匹配的規則對應的 NodeProcessor 是 GenMRTableScan1,它會創建一個 MapRedTask

SelectOperator 找到的 Processor 爲 GenMROperator,這個 Processor 僅僅保存了一下SelectOperator 和對應的 GenMRProcContext$GenMapRedCtx 的映射關係

ReduceSinkOperator 對應的 NodeProcessor: GenMRRedSink1

上面說過,以創建Task時,如遇到處理的節點爲ReduceSinkOperator,就直接根據它的子Operator 來生成Reduce Task,這就是 GenMRRedSink1 來完成的。

具體來說,GenMRRedSink1 將這個 GroupByOperator 作爲 reducer,把它存入當前任務中。當前任務就是剛纔處理TableScanOperator時創建的 Task。


所有節點處理完後會生成所有的Task,此時 PhysicalOptimizer 會再優化一次。它遍歷的其實還是個DAG,不過這時節點是 Task了。


至此,Task已經創建,可以着手創建Mapeduce Job 了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章