🗒️SparkSQL内核剖析 第五、六章
2023-6-30
| 2023-7-6
字数 1504阅读时长 4 分钟
type
status
date
slug
summary
tags
category
icon
password

第五章 SparkSQL 逻辑计划(LogicalPlan)

逻辑计划阶段在整个流程中起着承前启后的作用。在此阶段,字符串形态的 SQL 语句转换为树结构形态的逻辑算子树,SQL 中所包含的各种处理逻辑(过滤、剪裁等)和数据信息都会被整合在逻辑算子树的不同节点中。逻辑计划本质上是一种中间过程表示,与 Spark 平台无关,后续阶段会进一步将其映射为可执行的物理计划。
Spark SQL 语句经过 SparkSqlParser 解析生成 Unresolved LogicalPlan,到最终优化成为 Optimized LogicalPlan,这个流程主要经过三个阶段。
notion image
具体来讲,这个阶段所完成的工作分别如下: 1)由 SparkSqlParser 中的 AstBuilder 执行节点访问,将语法树的各种 Context 节点转换成对应的 LogicalPlan 节点,从而成为一棵未解析的逻辑算子树 Unresolved LogicalPlan,此时的逻辑算子树是最初形态,不包含数据信息与列信息等。 2)由 Analyzer 系列的规则作用在 Unresolved LogicalPlan 上,对树上的节点绑定各种数据信息,生成解析后的逻辑算子树 Analyzed LogicalPlan 3)由 Spark SQL 中的优化器 Optimizer 将一系列优化规则作用到上一步生成的逻辑算子树中,在确保结果正确的前提下改写其中的低效结构,生成优化后的逻辑算子树 Optimized LogicalPlan
以下部分参考其他博客,原书讲解实在是太复杂了。

AstBuilder 机制:生成 Unresolved LogicalPlan

我们先看看 AstBuilder 中的代码:
代码中会先判断是否有 FROM 子语句,有的话会去生成对应的 Logical Plan,再调用 withQuerySpecification() 方法,而 withQuerySpecification() 方法是核心的方法。它会处理包括 SELECT,FILTER,GROUP BY,HAVING 等子语句的逻辑。使用 scala 的模式匹配,匹配不同的子语句生成不同的 Logical Plan
LogicalPlan 继承自 TreeNode,所以本质上 LogicalPlan 就是一棵树。
而实际上, LogicalPlan 还有多个子类,分别表示不同的 SQL 子语句。
  • LeafNode,叶子节点,一般用来表示用户命令
  • UnaryNode,一元节点,表示 FILTER 等操作
  • BinaryNode,二元节点,表示 JOIN,GROUP BY等操作
看看一个测试案例,简单生成一个临时的 VIEW,然后直接 SELECT 查询这个 VIEW。代码如下:
最终经过 parse SQL 后会变成如下的内容:
这个 Project 是 UnaryNode 的一个子类(SELECT 是一元节点),表明我们要查询的字段是 key。
通过 SQL parse 生成的这棵树,叫 Unresolved LogicalPlan,这里的 Unresolved 的意思说,还不知道 src 是否存在,或它的元数据是什么样,只有通过 Analysis 阶段后,才会把Unresolved 变成 Resolved LogicalPlan。这里的意思可以理解为,读取名为 src 的表,但这张表的情况未知,有待验证。

Analyzer 机制:生成 Analyzed LogicalPlan

一条语句 SELECT col FROM sales,当我们不知道 col 的具体类型(Int,String,还是其他),甚至是否在 sales 表中有col这一个列的时候,就称之为是 Unresolved 的。
而在 analysis 阶段,就是将 Unresolved 的变成 Resolved 的。Spark SQL 通过使用 Catalyst rule 和 Catalog 来跟踪数据源的 table 信息。并对 Unresolved 应用如下的 rules(rule 可以理解为一条一条的规则,当匹配到树某些节点的时候就会被应用)。
analysis 阶段的流程:
  • Catalog 中,查询 Unresolved LogicalPlan 中对应的关系(relations)
  • 根据输入属性名(比如上述的 col 列),映射到具体的属性
  • 确定哪些属性引用相同的值并赋予它们唯一的 exprId
  • Propagating and coercing types through expressions,是对数据进行强制转换,方便后续对1 + col 这样的数据进行处理。

Optimizer 机制:生成 Optimized LogicalPlan

Optimizer 以及之后的模块都只会在触发了 action 操作后才会执行。优化器是用来将 Resolved LogicalPlan 转化为 Optimized LogicalPlan 的。
Optimizer 就是根据大佬们多年的 SQL 优化经验来对语法树进行优化,比如谓词下推、列值裁剪、常量累加等。优化的模式和 Analyzer 非常相近,Optimizer 同样继承了RuleExecutor,并定义了很多优化的 Rule。

第六章 Spark SQL 物理计划(PhysicalPlan)

在 SparkSQL 中,物理计划用 SparkPlan 表示,从 Optimized LogicalPlan 传入到 SparkSQL 物理计划提交并执行,主要经过 3 个阶段,这 3 个阶段分别产生 Iterator[PhysicalPlanSparkPlanPrepared SparkPlan,其中 Prepared SparkPlan 可以直接提交并执行。
notion image
这 3 个阶段所做的工作分别如下:
  1. SparkPlanner 将各种物理计划策略(Strategy)作用于对应的 LogicalPlan 节点上,生成 SparkPlan 列表(注: LogicalPlan 可能产生多种 SparkPlan
  1. 选取最佳的 SparkPlan,在 Spark2 版本中的实现较为简单,在候选列表中直接用 next() 方法获取第一个
  1. 提交前进行准备工作,进行一些分区排序方面的处理,确保 SparkPlan 各节点能够正确 执行,这一步通过 prepareForExecution()方法调用若干规则 Rule 进行转换
 
  • Spark
  • SparkSQL内核解析
  • SparkSQL内核剖析 第四章Hudi|CDC构建增量数仓
    Loading...