Spark SQL 解析-转换-执行过程

目录

 

前文

正文

1.概述

2. 抽象语法树生成

3.Unresolved Logic Plan 逻辑执行计划生成

4. Analyzed Logical Plan 逻辑执行计划生成

5.Optimized Logic Plan 逻辑执行计划生成

6.SparkPlan 物理执行计划的生成


前文

     Spark SQL以及Dataset体系在Spark中具有越来越重要的作用,基于RDD的体系正在被弱化,使用Dataset或者SQL编写的代码,甚至可以经过稍微修改之后迁移到Structure Streaming中进行执行。而且语法解析、语义解析和执行在很多地方也会被用到,比如规则引擎的解析和执行就可以基于语句来实现。

     闲暇时间阅读了SparkSQL的一些书籍和资料,笔记如下。

正文

1.概述

    用户编写的SQL是无法直接被底层计算框架执行的,必须要经过几个转换阶段,转变成框架能够识别的代码或者类对象,在Spark中,一般需要经过以下几个步骤,分为逻辑执行计划部分和物理执行计划部分。

   SQL Query,需要经过词法和语法解析,由字符串转换为,树形的抽象语法树, 通过遍历抽象语法树生成未解析的逻辑语法树(unresolved logic plan),对应SQL解析后的一种树形结构,本身不包含任务数据信息,需要经过一次遍历之后,转换成成包含解析后的逻辑算子树(Analyzed LogicPlan),本身携带了各种信息,最后经过优化后得到最终的逻辑语法树(Optimized LogicPlan)。  

    不管解析被划分为几步,在Spark 执行环境中,都要转化成RDD的调用代码,才能被spark core所执行,示意图如下:

2. 抽象语法树生成

   一般的从SQL语句语句转换成抽象的树状结构,需要经过词法分析和语法分析两个过程,实现较为繁琐,但是随着编译理论的成熟,开发人员可以借助各种各样的生成器,来实现词法分析和语法解析。

    spark中使用的框架为Anylr 4,通过脚本文件进行SQL 关键字和语法的定义,然后通过框架来实现词法分析和语法分析,详情可见Antlr 百科,通过编译解析Antlr的脚本定义文件,我们可以获得如下几个重要的文件:

a.****Lexer 词法解析器

b.****Parser  语法解析器   

c. ****BaseVisitor  访问遍历文件

   我们需要做的,就是在  ****BaseVisitor  文件中,编写我们的访问处理逻辑,比如:遇到max、min和add关键字的时候,应该如何做。Spark 生成的****BaseVisitor类的全名为:SqlBaseBaseVisitor ,AstBuilder 继承自SqlBaseBaseVisitor,实现了遍历抽象语法树,生成逻辑执行计划的逻辑,SparkSqlAstBuilder则添加了一些DDL的操作,具体继承关系如下:

举例:

sql 语句:select name from student where age >18;

生成抽象语法树:

3.Unresolved Logic Plan 逻辑执行计划生成

当我们获得上一节得到的抽象语法树之后,就可以使用SparkSqlAstBuilder(继承自SqlBasebaseVisitor 访问者模式)进行遍历了,调用的方法为visitSingleStatement方法,该方法的代码如下,因为singleStatement为根节点,无任何逻辑代码,所以直接递归遍历子节点即可:

直到遍历到关键Context节点的时候,比如QuerySpecificationContext的时候,需要按照顺序遍历三个分支,生成逻辑执行计划,其访问方法为visitQuerySpecification,源码如下:

from其实是返回一个relation,代表from的表信息,withQuerySpecification会携带relation表信息,继续向下进行遍历解析,解析顺序如下所示:

(1) 解析from分支,对应val from =  —— 段代码,创建UnresollvedRelation 

(2)withQuerySpecification()方法的调用,解析where中的过滤条件expresstion,创建Filter 逻辑执行计划

  (3) 解析select *  部分,对最后的输出,进行列的裁剪,创建Project 逻辑执行计划

   (4) 构建完整化逻辑执行计划

最后解析完毕的逻辑执行计划可视化如下:

4. Analyzed Logical Plan 逻辑执行计划生成

       该过程的执行,实际上是从unresolved logic plan到analyzed logical plan的转化过程,通过在遍历的过程中,应用各种rule对其进行转化,驱动应用rules的类为RuleExecutor,其包含了一组Seq[Batch],每一个Batch中包含了一组Rule和strstegy,一个是转换规则,一个是规则应用次数,结构如下:

    RuleExecutor的驱动方法为execute()方法,其实现逻辑如下,Batch遍历一遍,但是每条rule会被执行多次(这是缩减的代码,全量代码可以查看RuleExecutor.scala这个类):

    所以本阶段最重要的就是定义转换规则Rules,目前 spark 2.1 Rules定义了6个Batch,共有34条内置规则Rules,包含表的解析,列的解析和数值类型转换等。

    从之前得到的unresolved logic plan转化到analyzed logic plan需要经历如下步骤:

    a.解析unresolvedRelation 通过catalog获取表的列信息,并为student 添加别名别点

    b.解析Filter 节点,解析age列信息(添加age列在数据表的的列位置信息),转换18的数据类型

    c.解析Project节点,添加name列信息(添加列name在数据表中的列信息)

    解析后的logic plan如下所示:

5.Optimized Logic Plan 逻辑执行计划生成

    逻辑计划优化器(Optimizer) 实现原理同Analyzed 继承自RuleExecutor,通过应用Seq(Batch) 优化规则,实现逻辑树的优化过程,总共2个Batch和4个Spark特有的优化规则,例如:别名消除、算子列裁剪下推和算子组合等。

    因为SQL语句简单,所以在本步骤,只应用了别名消除规则,如下:
 

6.SparkPlan 物理执行计划的生成

物理计划是直接能够进行执行的方法,也就是SparkPlan类,其中该类包含了几个比较重要的方法:
a.doExecute   物理计划执行调用的方法

b.requirdChildDistrbution  约束子节点的数据分布(分区)情况是否符合要求

c.outputPartitionng  按照规定的数据分布进行输出

物理计划的生成方式跟之前的方式类似,包含一个驱动类和转换策略,驱动类为SparkPlanner,驱动方法为plan(),传入一个SparkPlan,应用驱动类内部的Seq[Strategy],策略会对SparkPlan进行匹配,向物理执行计划进行转换,

转换之后的物理执行计划如图所示,之后经过一些准备操作之后,便可以提交执行了:
 

猜你喜欢

转载自blog.csdn.net/u013560925/article/details/90344230