spark2.2.0源码学习过程记录:Day8

本文详细解析了Apache Spark SQL的执行流程,从SQL语句的解析到生成Logical Plan,再到DataFrame的创建过程。重点关注了SparkSession及其内部组件如何协作完成这一系列任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、《apache spark 源码剖析》浏览第六、七、八、九章
后面的几章中只准备学习其中的spark sql部分,所以首先全部浏览了一下,再回过头来看第七章

2、读《apache spark 源码剖析》第七章第1节、第2.1节
SQL语句在分析执行过程中会经理几个步骤:(1)语法解析。(2)操作绑定。(3)优化执行策略。(4)交付执行。

3、源码学习
从书中看出入口类为SparkContext,但是看代码中,在新版本已经被SparkSession代替,所以直接看SparkSession,书中sql方法返回的SchemaRdd,现在也已经变成了DataFrame

类SparkSession
sql方法首先调用sessionState.sqlParser.parsePlan(sqlText)方法生成LogicalPlan
那么首先要找到这个sqlParser的具体实例类
看sessionState创建的地方,先调用SparkSession.sessionStateClassName方法来确定BaseSessionStateBuilder的具体实现类,我这里假定使用的hive,那么具体类为HiveSessionStateBuilder;然后调用SparkSession.instantiateSessionState,用反射方法创建一个HiveSessionStateBuilder,并调用他的build方法创建一个SessionState实例

类HiveSessionStateBuilder 继承自BaseSessionStateBuilder

类BaseSessionStateBuilder
在BaseSessionStateBuilder中,创建一个sqlParser要调用extensions.buildParser(session, new SparkSqlParser(conf))方法,SparkSqlParser类是一个spark sql的解析器

类SparkSessionExtensions
SparkSessionExtensions的buildParser是处理所有的外部注入的sqlParser,如果没有的话,就是返回刚才创建的SparkSqlParser

小细节
type
在SparkSessionExtensions类的开头有type ParserBuilder = (SparkSession, ParserInterface) => ParserInterface,代码看了半天没明白,网上找了解释
说的非常明白,把后面的ParserBuilder都替换成(SparkSession, ParserInterface) => ParserInterface就一目了然了
比如创建ParserInterface的buildParser方法(从上下文可以知道这个builder就是ParserBuilder ):
parserBuilders.foldLeft(initial) { (parser, builder) =>
builder(session, parser)
}
替换以后就很明白了,其实就是一个构造函数
parserBuilders.foldLeft(initial) { (parser, (SparkSession, ParserInterface) => ParserInterface) =>
(SparkSession, ParserInterface) => ParserInterface(session, parser)
}

foldleft
在SparkSessionExtensions类的buildParser方法中用到了buildParser函数
网上摘录的fold解释,foldleft类似
val numbers = List(5, 4, 8, 6, 2)
numbers.fold(0) { (z, i) =>
z + i
}
// result = 25
  List中的fold方法需要输入两个参数:初始值以及一个函数。输入的函数也需要输入两个参数:累加值和当前item的索引。那么上面的代码片段发生了什么事?
  代码开始运行的时候,初始值0作为第一个参数传进到fold函数中,list中的第一个item作为第二个参数传进fold函数中。
  1、fold函数开始对传进的两个参数进行计算,在本例中,仅仅是做加法计算,然后返回计算的值;
  2、Fold函数然后将上一步返回的值作为输入函数的第一个参数,并且把list中的下一个item作为第二个参数传进继续计算,同样返回计算的值;
  3、第2步将重复计算,直到list中的所有元素都被遍历之后,返回最后的计算值,整个过程结束;


类AbstractSqlParser
下面接着前面的说,调用了sqlParser(即SparkSqlParser)的parsePlan方法,这个类中没有,在他的父类AbstractSqlParser中找到,这个方法为给定的sql语句创建LogicalPlan
在这个方法中首先调用了parse(sqlText)方法
在这个方法中,首先创建ANTLRNoCaseStringStream对象,这个对象继承自ANTLRInputStream,不同之处是ANTLRNoCaseStringStream把所有字符串改成了大写
创建ANTLRNoCaseStringStream对象后,连续创建了SqlBaseLexer、CommonTokenStream、SqlBaseParser对象,其中SqlBaseLexer、SqlBaseParser对象在源码中找不到,于是上网查了一下,发现是antler自动生成的(链接 http://www.jianshu.com/p/0aa4b1caac2e
生成SqlBaseParser后,调用传入的toResult,在这里调用了sqlBaseParser的singleStatement方法创建一个SqlBaseParser.SingleStatementContext对象,然后将其作为参数,调用astBuilder.visitSingleStatement,这个astBuilder的具体实现类是SparkSqlAstBuilder,但是其中没有visitSingleStatement方法,该方法在其父类AstBuilder中,其中调用了visit方法,最终调用了AbstractParseTreeVisitor类的visit方法,后面有点乱了,需要学习antler才能继续,先不钻了

最终在SparkSession的sqlParser.parsePlan方法里取得了LogicalPlan,然后调用Dataset.ofRows方法,这个方法属于书中下一节的内容

类ANTLRInputStream
这个类是antlr包中的,从maven下载源码没下成功,于是直接到github下载了zip包,作为源码导入


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值