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 是抽象类