Spark SQL Catalyst
A Deep Dive into Spark SQL Catalyst Optimizer
Spark的应用层, ML, GraphFrames 和StructuredStreaming对外的高级应用, 较RDD来说Spark SQL提供了一系列高级API: sql语法和DSL.
Spark SQL: SQL layer, DataFrame/Dataset, 由Catalyst 支撑, 并串联Spark Core(RDD)编程模型
所以SparkSQL中 Catalyst具有非常重要的地位.
val df = data.groupBy("dept").avg("ag")
spark.sql( "select dept, avg(age) from data group by 1 ")
DSL 与Pandas的语法非常像.
SQL/DSL 称为 Structure API. 特点是开发容易,学习门槛低,而且关键是性能比RDD快75% .
局限性,有一定的表达范式, 但大多数计算场景,都是可以满足和覆盖的.
为什么 Spark SQL优化过后比RDD还快?
解密Catalyst, Spark SQL的优化器
工作流程:
-
Parser, 使用ANTLR 4 将 SQL字符串解析为抽象语法树AST, 最终输出 unresolved logical plan (ULP)
-
Analyzer, 借助catalog将ULP进一步解析为Logical Plan (LP)
-
Optimizer 根据一些优化策略(RBO, CBO)得到 optimized logical plan (OLP), 主要是针对LP进行剪枝,合并,进而删除一些无用计算,或合并一些计算.
-
SparkPlanner, 生成物理计划及执行 (OLP仍是逻辑的, 要将OLP转变为Physical Plan)
-
Code generation, 形成最终的字节码, RDD的执行DAG.
(TODO: 怎么的优化, 怎么的剪枝和合并, 需要细探入 CBO)
Trees, 用户程序的抽象表达
比如用户提交了一个sql,
这个sql当中存在5个表达式 :
词法层面,
- Expressions: 每个表达式表示一个新值,基于输入数据计算而来
- Attributes: 每个dataset中的field 或者 as别名产生的新属性
语法层面,对于数据的操作算子,则可以抽象出一棵这样的树: 每个node表示一种数据算子
这个层面是逻辑计划(Logical Plan), 不会涉及到如何完成计算的实现.
Logical Plan的output是若干个 attribute组成的列表, 比如某个节点输出 [id, v]
Unresolved LogicalPlan 基本上涵盖了SQL要做的骨干动作.
Physical Plan 也是一棵树, 描述了数据集上要执行哪些计算., Physical是可执行的, 和具体的类是对应的.
Transformations
Transform 是一种定义在dataset上的偏函数, 即只会作用dataset的一部分数据(subset),而非全局使用.
val expression: Expression = ...
expression.transform {
case Add(Literal(x, IntegerType), Literal(y, IntegerType)) =>
Literal(x + y)
}
Catalyst 对树的变换操作分为两个类, 第一类变换是不改变树的类型, 原来是什么,变换之后还是什么;
- Expression => Expression
- Logical Plan => Plogical Plan
- Physical Plan => Physical Plan
第二类是改变类型的, 例如将一棵LogicalPlan树转变为Physical Plan
如 object BasicOperators extends Strategy
sparkSQL将字符串切分成一个一个token,根据语义规则解析为一个抽象语法树. 和Hive,Presto一样,Spark SQL也采用 ANTLR 完成解析.
比如 1 + 2 + score.math_score
这个表达式我们是怎么分析的.
Analyzer
Analyzer 会再次遍历整个AST,对树上的每个节点进行数据类型绑定
和函数绑定
从catalog中获取元数据信息,表信息\字段. ULP 基础 + 元数据 = LP
Catalog, dataset column schema ...
这一步使用 Rule Executor 完成 ULP到LP的变换.
Optimizer
优化场景举例
常数折叠
谓词下推
列剪裁, 减少不必要的数据扫描,减少IO cost
源码
LogicalPlan 继承自QueryPlan,包含了两个成员变量+17个方法. 两个成员变量,
resolved,标记该LogicalPlan是否经过解析(布尔值)
LeafNode
LogicalPlan 是抽象类