hive编译部分的源码结构
很少在博客里写翻译的东西, 这次例外. 原文在这儿. 译文掺杂了些自己的表述。
解析器(Parser)
解析器 由antlr生成, 文法定义在Hive.g文件中。它的功能是将查询字符串翻译成抽象语法树(Abstract Syntax Tree, 简称AST).
语法分析器(Semantic Analyzer)
语法分析器将AST转换成内部查询形式,此形式为查询块(Query Block), 而不是一棵操作符树(Opertator Tree).它还验证查询语句中的列名, 符号"*" 等. 同时这一环节还进行类型检查, 隐式类型转换.如果被查询的表是带分区(Partition)的表,则所有关于该表的表达式都将被收集起来,以备裁剪不必要的分区时使用;如果查询语句包含采样(Sampling)操作,也会收集这些表达式.
逻辑计划生成器(Logic Plan Generator)
逻辑计划生成器将内部查询形式(即上文提到过的查询块)转换成逻辑计划。逻辑计划是一棵操作符树。其中部分操作符是关系代数操作符,例如filter, join操作符。还有部分操作符是hive特有的操作符,它们将被翻译为mapreduce作业, 例如,reduceSink操作符。它出现在map与reduce的分界处。
此环节还包含优化器。优化器修改查询计划以提高查询的效率。例如:把一系列join操作合并到一个join中;groupby操作的map端聚合;将groupby分为两步,以防数据倾斜,造成某个reducer负担过重,成为瓶颈。
每个操作符,都包含一个描述符(descriptor)。描述符是可序列化的对象。查询计划生成器(Query Plan Generator)
即数据库理论中的物理查询计划生成器。它将逻辑计划转换成一系列的map-reduce任务(见ql/exec/MapRedTask类)。具体操作是递归访问操作符树,将它们分成一系列序列化的map-reduce任务, 然后将任务提交给hadoop分布式系统。reduceSink是map与reduce的分界线,它的描述符包含归约键(reduction keys), 归约键是mapper的输出键,即也是reduce的输入键。如果查询中包含采样/分区, 则也会有相应的计划。计划被序列化到一个plan.[0-9]+文件里,它是一个xml格式的文件。
Distinct的改造
SemanticAnalyzer.genGroupByPlanReduceSink() 方法根据GroupBy与distinct function信息组合成了redcueKeys,再将它放入reduceSinkDesc对象中(reduceSinkDesc.keyCols).这个keyCols的类型是ArrayList<exprNodeDesc>,即表达式数组,其实它应该为一个ArrayList<ArrayList<exprNodeDesc>> 或者HashMap<String, ArrayList<exprNodeDesc>>以支持多种key输出
reduceSinkDesc被ExecDriver序列化提交到hive.scratchdir目录下的plan.[0-9]+文件. hive.scratchdir一般在hive-site.xml中定义,是hive在hdfs上的一个存放临时文件的目录. ExecMapper与ExecReduce在configure的时候, 会读取这些plan.[0-9]+文件, 反序列化mapRedWork对象, 初始化各Operator等.
将ReduceSinkOperator.keyEval改成ExprNodeEvaluator[][]的二维数组以支持多个key输出
Map会以MapOperator为操作符树的根结点, Reduce一般以GroupByOperator为操作符树的根结点