QueryExecution
在调用分析器之前,首先创建QueryExecution. QueryExecution 是spark执行查询的主链路。
最终调用的是alalyzed(),
可以发现Analyzer继承了RuleExecutor
RuleExecutor
Rule是一系列的规则的接口类,比如分析器的各种分析规则,优化器的各种规则,执行器的各种规则等等。
RuleExecutor 就是各种不同Rule匹配逻辑执行计划树结构并且生成新的树结构的生成器。
在RuleExecutor的实现子类(如Analyzer和Optimizer)中会定义Batch(每个Batch代表着一套规则),Once(只执行一次的策略)和FixedPoint(执行固定次数的策略)。
executo()的执行逻辑就是批量根据策略调用Rule的apply方法。
Analyzer
Analyzer的规则列表分为Analyzer内部的和基于hive扩展的两个类。基于hive扩展的在HiveSessionStateBuilder中。
HiveSessionStateBuilder扩展的规则主要是和hiveCatalog进行绑定。
常见的rule
LookupFunctions
查找函数的,一般的场景都是查询hive-metastore中的funcs。这个地方就需要和HiveExternalCatalog进行绑定,通过hive-client查询函数的名称。
先看一下语法解析层函数是怎么解析成UnresolvedFunction的。如果不清楚可以参考https://blog.csdn.net/strawhat2416/article/details/120293413
接下来看LookupFunctions函数,对于unresolvedFunction,判断是否能够从catalog里面找到,如果找不到就报错。
这个地方首先判断function注册中是否存在,如果不存在再去hiveExternalCatalog里面获取。
functionRegistry.functionExists 判断函数是否存在,最终调用了SimpleFunctionRegistry.functionBuilders.
最终调用了HiveExternalcatalog
所有的函数其实都是从hive-client里面获取的。而临时的function是查询继承UDFRegistration来判断的。
ResolveRelations
relations 就类似于我们的hive表,在Analyzer-ResolveRelations阶段,会把relation解析为SubqueryAlias(UnresolvedCatalogRelation)。 后面会把UnresolvedCatalogRelation解析为CatalogRelation. 这个阶段里面也是和HiveExternalCatalog进行绑定,查询表名以及meta信息。
下面就是从spark-history中截取的一段Analyzed Logical Plan
FindDataSourceTable
如果是hive表,会转换成HiveTableRelation.这个会在后面有用。
RelationConversions
读取场景下,非分区生成HadoopFsRelation.
**所以在Analyzer阶段,关于读取hive表,到底生成什么样的relation. 在不同的版本生成不同。
几个比较重要的配置:
- spark.sql.orc.impl 默认是hive。 在spark.2.4之后的版本默认是native.
- spark.sql.orc.enableVectorizedReader spark.2.3之前的版本是false, 之后的版本是true
- spark.sql.hive.convertMetastoreOrc=false, 在spark.2.4之后的版本是true**