
以Hive目前原生支持计算引擎MapReduce为例,具体处理流程如下:
HQL解析生成AST语法树 Antlr定义SQL的语法规则,完成SQL词法和语法解析,将SQL转化为抽象语法树AST Tree 语法分析得到QueryBlock 遍历AST Tree,抽象出查询的基本组成单元QueryBlock 生成逻辑执行计划 遍历QueryBlock,翻译为执行操作树Operator Tree Logical Optimizer Operator进行逻辑优化 逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量 生成物理执行计划Task Plan 遍历Operator Tree,翻译为MapReduce任务 物理优化Task Tree,构建执行计划QueryPlan 物理层优化器进行MapReduce任务的变换,生成最终的执行计划 表以及其他操作鉴权 执行引擎执行
在Hive Query整个生命周期中,会有如下钩子函数被执行:
HiveSemanticAnalyzerHook的preAnalyze
在Driver开始run之前,HQL经过解析会进入编译阶段的语法分析,而在语法分析前会经过钩子HiveSemanticAnalyzerHook的preAnalyze方法处理。该钩子函数由hive.semantic.analyzer.hook配置,钩子需实现org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHook接口。
HiveSemanticAnalyzerHook的postAnalyze
生成执行计划之前的redactor钩子
该钩子由hive.exec.query.redactor.hooks配置,多个实现类以逗号间隔,钩子需继承org.apache.hadoop.hive.ql.hooks.Redactor抽象类,并替换redactQuery方法。
task执行前的preExecutionHook
在执行计划QueryPlan生成完,并通过鉴权后,就会执行具体的task,而task执行之前会经过一个钩子函数,钩子函数由hive.exec.pre.hooks配置,多个钩子实现类以逗号间隔。实现方式:
通过实现该接口的run方法,执行所有的pre-execution hooks
// Pre/Post Execute Hook can run with the HookContextpublic interface ExecuteWithHookContext extends Hook {/** hookContext: The hook context passed to each hooks.* HookContext带有执行计划、Hive的配置信息、Lineage、UGI、提交的用户以及输入输出表等信息*/void run(HookContext hookContext) throws Exception;}
public interface PreExecute extends Hook {/*** The run command that is called just before the execution of the query.* SessionState、UGI、HQL输入表及分区信息,HQL输出表、分区以及本地和hdfs文件目录信息*/@Deprecatedpublic void run(SessionState sess, Set<ReadEntity> inputs,Set<WriteEntity> outputs, UserGroupInformation ugi) throws Exception;}
task执行失败时,Hive会调用这个hook执行一些处理措施。该钩子由参数hive.exec.failure.hooks配置,多个钩子实现类以逗号间隔。需实实现org.apache.hadoop.hive.ql.hooks.ExecuteWithHookContext接口。
task执行完成时的postExecutionHook
在task任务执行完成后执行。如果task失败,会先执行ON_FAILURE_HOOKS,之后执行postExecutionHook,该钩子由参数hive.exec.post.hooks指定的hooks(多个钩子实现类以逗号间隔)执行post execution hooks。实现方式:
1)实现org.apache.hadoop.hive.ql.hooks.ExecuteWithHookContext
2)实现org.apache.hadoop.hive.ql.hooks.PostExecute
ExecuteWithHookContext和PostExecute跟分别与上述task执行前的preExecutionHook、PreExecute对应,这里不再赘述。
HiveDriverRunHook的postDriverRun
ATSHook:实现了ExecuteWithHookContext,将查询和计划信息推送到Yarn App Timeline Server。
DriverTestHook:实现了HiveDriverRunHook的preDriverRun方法(对postDriverRun是空实现),用于打印输出的命令。
EnforceReadOnlyTables:pre execute hook,实现了ExecuteWithHookContext,用于阻止修改只读表。
LineageLogger:实现了ExecuteWithHookContext,它将查询的血统信息记录到日志文件中。LineageInfo包含有关query血统的所有信息。
PreExecutePrinter和PostExecutePrinter:pre和post hook的示例,它将参数打印输出。
PostExecTezSummaryPrinter:post execution hook,实现了ExecuteWithHookContext,可以打印Hive Tez计数器的相关信息。
PostExecOrcFileDump:post execution hook,实现了ExecuteWithHookContext,用于打印ORC文件信息。
UpdateInputAccessTimeHook:pre execution hook,可在运行查询之前更新所有输入表的访问时间。
特别强调一下LineageLogger和LineageInfo,对于做Hive血缘关系分析很有参考价值,当然Hive血缘分析不是本篇文章的重点,这里先不做展开。
通过对上面Hive中hook的执行"位置"和作用,以及Hive本身实现的一些Hook,分析可知:自定义hook,比如实现一个pre execution hook。
首先在maven的pom中引入hive-exec的依赖,如:
<dependency><groupId>org.apache.hive</groupId><artifactId>hive-exec</artifactId><version>2.1.0</version></dependency>
此外,还需创建一个实现ExecuteWithHookContext的类,实现其中的run方法,并设置相应的参数,使自定义的hook类生效。
最后,通过一张图,来对Hive Hook做个总结:

Hive Join优化
Apache Hive





