當(dāng)一條 sql 語句被 SparkSqlParser 解析為一個(gè) unresolved logicalPlan 后乘碑,接下來就會(huì)使用 Analyzer 進(jìn)行 resolve宙攻。所謂的 resolve 也就是在未解析的 db、table、function癌淮、partition 等對(duì)應(yīng)的 node 上應(yīng)用一條條 Rule(規(guī)則)來替換為新的 node肚菠,應(yīng)用 Rule 的過程中往往會(huì)訪問 catalog 來獲取相應(yīng)的信息健蕊。
先來看看在解析過程中涉及到的幾個(gè)主要類菱阵,以便為之后的詳細(xì)分析做好鋪墊。
一缩功、主要類
上圖(省略了諸多成員晴及,方法)列舉了解析一個(gè) unresolved logicalPlan 時(shí)涉及的主要類及其之間的關(guān)系,其中 Analyzer 是解析的入口嫡锌,其定義如下:
class Analyzer(
catalog: SessionCatalog,
conf: SQLConf,
maxIterations: Int)
extends RuleExecutor[LogicalPlan] with CheckAnalysis
先來看看幾個(gè)主要的相關(guān)的類
1.1虑稼、SessionCatalog
SparkSession 使用的 catalog,是 spark 與底層 megastore(比如 Hive Metastore)的橋梁势木,并管理著 SparkSession 的臨時(shí)表傀广、view 以及函數(shù)翠订。由于會(huì)有并發(fā)訪問,該類是線程安全的。
如上圖中該類的構(gòu)造函數(shù)歼冰,該類借助 ExternalCatalog答憔、GlobalTempViewManager攘已、FunctionRegistry女蜈、FunctionResourceLoader 等類型的成員實(shí)現(xiàn)對(duì) db、table板驳、partition又跛、function 的 CURD 等功能
1.1.1、ExternalCatalog
catalog 接口若治,包含 functions慨蓝、partitions、tables 和 databases端幼。僅適用于非臨時(shí)的項(xiàng)目礼烈,線程安全。這是一個(gè)用來與外部系統(tǒng)交互的 external catalog(比如與 Hive Megastore 交互的實(shí)現(xiàn)是 HiveExternalCatalog
静暂,你也可以實(shí)現(xiàn)自己的 meta store 及相應(yīng)的 ExternalCatalog)济丘。當(dāng) database 不存在的時(shí)候谱秽,要拋出 NoSuchDatabaseException
洽蛀。主要包含以下幾類方法:
- database 相關(guān):checkExists、create疟赊、alter郊供、list、drop近哟、alter驮审、
use database
- table 相關(guān):checkExists、create、alter疯淫、list地来、drop、alter schema熙掺、
rename
- partition 相關(guān):load(加載數(shù)據(jù)到一個(gè) partition)未斑、load 動(dòng)態(tài)分區(qū)、create币绩、drop蜡秽、rename、alter缆镣、get芽突、list
- function 相關(guān):create、drop董瞻、alter寞蚌、rename、checkExists力细、list
1.1.2睬澡、GlobalTempViewManager
一個(gè)線程安全的全局的 temp views 的 manager,提供對(duì)其原子的操作眠蚂,比如 create煞聪、update、remove 等逝慧。注意昔脯,view 的名字是大小寫敏感的。其包含對(duì)于 temp view 的方法:
- get
- create
- update
- remove
- rename
- list
- clear
1.1.3笛臣、FunctionRegistry
Analyzer 用來查找 UDF 的 catalog云稚,線程安全并且對(duì) db name 大小寫敏感。包含 function 相關(guān)的方法:
- register
- create or replace
- look up
- list
- drop
- checkExists
- clear
1.1.4沈堡、FunctionResourceLoader
用來加載一個(gè)函數(shù)要使用的資源
1.2静陈、RuleExecutor
定義了一個(gè) rules 執(zhí)行框架,即怎么把一批批規(guī)則應(yīng)用在一個(gè) plan 上得到一個(gè)新的 plan诞丽。具體是怎么做的鲸拥,會(huì)在下面詳細(xì)展開。
1.3僧免、SQLConf
用來 get刑赶、set SQL 相關(guān)的配置、參數(shù)懂衩。其伴生 object 包含了 spark sql 的所有參數(shù)及其類型撞叨、說明金踪、默認(rèn)值。而 class SQLConf 提供了這些參數(shù)牵敷、配置的 getter胡岔、setter 方法。
1.4枷餐、CheckAnalysis
用于對(duì) plan 做一些解析姐军,如果解析失敗則拋出用戶層面的錯(cuò)誤
二、如何解析
整個(gè)解析過程就是 Analyzer 通過繼承或者包含實(shí)例的方式將這些類串起來尖淘,去 catalog 中查詢信息并應(yīng)用一系列規(guī)則來將一個(gè) unresolved logicalplan 最終轉(zhuǎn)變?yōu)橐粋€(gè)新的 resolved plan 的過程奕锌。
2.1、規(guī)則是如何執(zhí)行的村生?
2.1.1惊暴、Rule
在說明規(guī)則是如何執(zhí)行之前,先說明什么是規(guī)則趁桃?規(guī)則均繼承了 abstract class Rule
辽话,包含了一個(gè) name 方法及 def apply(plan: TreeType): TreeType
方法,調(diào)用 apply 方法將一個(gè) plan 轉(zhuǎn)換成一個(gè)新的 plan卫病,這個(gè)新的 plan 往往與原來的 plan 有一些不同油啤,也有可能與執(zhí)行規(guī)則前相同。
2.1.2蟀苛、RuleExecutor
要把一個(gè) unresolved logicalPlan 解析為一個(gè) resolved logicalPlan益咬,需要執(zhí)行大量規(guī)則。那么帜平,這么多規(guī)則是如何組織的幽告?執(zhí)行順序是怎么樣的?這些問題都能在 RuleExecutor 類中找到答案裆甩。
2.1.2.1冗锁、Batch
類 RuleExecutor 看名字就知道是用來 execute rule 的。在其內(nèi)部定義了一個(gè) Batch 類嗤栓,用來表示 a batch of rules
冻河,即一組同類的不定長規(guī)則:
case class Batch(name: String,
strategy: Strategy,
rules: Rule[TreeType]*)
其中,strategy: Strategy
即規(guī)則的執(zhí)行策略茉帅,表示 Batch 最大執(zhí)行次數(shù)叨叙。 如果執(zhí)行了 maxIterations 次之前達(dá)到收斂點(diǎn)(在這里是執(zhí)行規(guī)則后 plan 沒有變化),也將停止担敌,不再繼續(xù)執(zhí)行 Batch摔敛。而每個(gè) Batch 的 maxIterations 都是經(jīng)驗(yàn)值廷蓉。
RuleExecutor 包含了一個(gè) protected def batches: Seq[Batch]
方法全封,用來獲取一系列 Batch马昙,這些 Batch 都會(huì)在 execute 中執(zhí)行。所有繼承 RuleExecutor(Analyzer 和 Optimizer)都必須實(shí)現(xiàn)該方法刹悴,即提供自己的 Seq[Batch]行楞。如果需要新增規(guī)則,只需要新增 Batch 或者再某個(gè) Batch 中新增規(guī)則即可土匀。整體的框架不用動(dòng)子房。
2.1.2.2、RuleExecutor#execute
讓我們來看看 Batch 和 rule 具體是怎么執(zhí)行的就轧,即 RuleExecutor#execute(plan: TreeType): TreeType
的邏輯:
有幾個(gè)關(guān)鍵點(diǎn):
- Batch 都是連續(xù)執(zhí)行的
- Batch 中的 rules 也是連續(xù)執(zhí)行的
- 當(dāng) Batch 執(zhí)行的次數(shù)達(dá)到其規(guī)定的最大執(zhí)行次數(shù)或執(zhí)行該 Batch 并未修改 plan证杭,則不再繼續(xù)運(yùn)行該 batch
三、Analyzer 的 Seq[Batch]
Analyzer 的 Seq[Batch] 如下:
lazy val batches: Seq[Batch] = Seq(
Batch("Hints", fixedPoint,
new ResolveHints.ResolveBroadcastHints(conf),
ResolveHints.RemoveAllHints),
Batch("Simple Sanity Check", Once,
LookupFunctions),
Batch("Substitution", fixedPoint,
CTESubstitution,
WindowsSubstitution,
EliminateUnions,
new SubstituteUnresolvedOrdinals(conf)),
Batch("Resolution", fixedPoint,
ResolveTableValuedFunctions ::
ResolveRelations ::
ResolveReferences ::
ResolveCreateNamedStruct ::
ResolveDeserializer ::
ResolveNewInstance ::
ResolveUpCast ::
ResolveGroupingAnalytics ::
ResolvePivot ::
ResolveOrdinalInOrderByAndGroupBy ::
ResolveAggAliasInGroupBy ::
ResolveMissingReferences ::
ExtractGenerator ::
ResolveGenerate ::
ResolveFunctions ::
ResolveAliases ::
ResolveSubquery ::
ResolveSubqueryColumnAliases ::
ResolveWindowOrder ::
ResolveWindowFrame ::
ResolveNaturalAndUsingJoin ::
ExtractWindowExpressions ::
GlobalAggregates ::
ResolveAggregateFunctions ::
TimeWindowing ::
ResolveInlineTables(conf) ::
ResolveTimeZone(conf) ::
TypeCoercion.typeCoercionRules(conf) ++
extendedResolutionRules : _*),
Batch("Post-Hoc Resolution", Once, postHocResolutionRules: _*),
Batch("View", Once,
AliasViewChild(conf)),
Batch("Nondeterministic", Once,
PullOutNondeterministic),
Batch("UDF", Once,
HandleNullInputsForUDF),
Batch("FixNullability", Once,
FixNullability),
Batch("Subquery", Once,
UpdateOuterReferences),
Batch("Cleanup", fixedPoint,
CleanupAliases)
)