目录
编译流程
获取AST
进行语义解析
小结:
前一篇文章中我梳理了HQL语句从提交到进入编译流程的一个简单过程,接下来我将数理在编译流程中的工作。
编译流程
总目标:编译流程由Driver 的compile(hql)函数实现。该函数将HQL 语句编译成执行计划,也称为Query Plan。
编译的过程还是比较复杂的。总结起来包括以下几个关键步骤:
1. 对HQL 做变量替换预处理;
2. 构造一个ParseDriver 对象做语法分析,将HQL 转换成AST;
3. 通过SemanticAnalyzerFactory 获得语义分析器,在AST 上完成类型检查、其它语义分析、优化等工作,最终生成Tasks;
4. 生成QueryPlan。
不过总的来讲,编译过程主要分为三大步骤,
- 根据SQL生成抽象语法树
- 进行语义分析
- 执行计划的生成
我在之前的工作中主要负责第二大步骤的分析。
获取AST
Hive主要是通过用ANTLR语法定义的词法和文法文件来进行解析,最后生成抽象语法树。通过ParseUtils中的parse方法来生成语法树,最后转向ParseDriver中的parse方法:
进行语义解析
语义分析主要通过 BaseSemanticAnalyzer 实现类中的 analyze 方法进行。
不同的hql语句会用不同的 BaseSemanticAnalyzer实现类来进行分析,前面我也汇总了一些语义分析器及其功能:
具体可查看博客6 :
一般我们常写的查询语句主要是通过 SemanticAnalyzer 中的 analyze 方法解析的。该方法最后又会转向各个语义分析器中的 analyzeInternal 方法。
不过要注意的是,这里的语义分析也包含了很多其他的功能,如优化和Task 生成等。
总的来说,上一步生成的AST,可以称之为编译的前段,后面的语义分析、优化、生成QP构成了编译流程的后段,AST是整个后段的输入。后段的流程如下:
1. 调用语义分析器sem.analyze(tree, context)完成AST 的语义分析
2. Logical Plan 生成:即,将AST 经过语义检查后,转换成Operator DAG,并将相关的信息记录在QB (也称为Logical Plan)中
3.Optimization:在Operator DAG 上进行优化变换;
4.Physical Plan 生成:将Operator DAG 变换成Task Dag,这就是最终的执行计划QueryPlan。
我在这里重点梳理对AST进行语义分析的内容:
①找到所有表、子查询的别名,并设置在aliasToTable、aliasToSubq 表中;
②找到所有内部clause 的结果的目标及其名字;
③建立clause 名字到其select 表达式AST 的映射关系;上面所有这些映射关系都保存在QB/QBParseInfo 中。
以上三步对应于doPhase函数,其大致内容结构如下:
更多详细的步骤分析在前面的文章中介绍了。
④获取源表、目标表、的元数据(主要是schema 等信息)
对应代码如下:
⑤调用genPlan()递归生成子查询的逻辑计划;
该部分主要由队友负责解读,根据了解,主要使用genPlan()实现,genPlan() 采用了深度优先的递归。
⑥进行后续的对QP的优化。
小结:
至此,我们就主要完成了HQL从进入用户接口,再到生成抽象语法树,再进行语义分析和计划生成的流程的梳理过程。