面向群友写文,哈哈
有点抽象,但群友们一定知道我在写什么
(原谅我,喜欢晒截图)
分享课上没有trace详细代码,这篇顺一下这块的代码。
sparksql生成解析后的逻辑执行计划时,会通过catalog把各个字段和元数据库绑定,也就说在ResolveLogical的阶段的字段是带了id的:
代码语言:javascript复制SELECT A,B FROM TESTDATA2
== Parsed Logical Plan ==
'Project ['A, 'B]
- 'UnresolvedRelation [TESTDATA2], [], false
== Analyzed Logical Plan ==
Project [A#3, B#4]
- SubqueryAlias testdata2
- View (`testData2`, [a#3,b#4])
- SerializeFromObject [knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).a AS a#3, knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).b AS b#4]
- ExternalRDD [obj#2]
可以看到从未解析到解析,字段由'Project ['A, 'B] --> Project [A#3, B#4]
那这个id是什么时候生成的呢?
id是在建表时或者创建临时视图时生成的。
我们以createOrReplaceTempView为例来看一下:
准备TESTDATA2测试数据时的逻辑——
1、SQLTestData 类中,生成testData2
2、SQLImplicits隐式转换把rdd转成DataSet
3、SQLImplicits 类的执行流程
SQLImplicits --> LowPrioritySQLImplicits -->newProductEncoder -->Encoders.product[T] --> ExpressionEncoder
下面图按顺序:
从上图可知会用到ExpressionEncoder类
4、ExpressionEncoder类的运行流程
sparksql源码中有很多操作是初始化类的时候做的
ExpressionEncoder.apply 这里计算:
代码语言:javascript复制val serializer = ScalaReflection.serializerForType(tpe)
val deserializer = ScalaReflection.deserializerForType(tpe)
--> new ExpressionEncoder[T](serializer, deserializer, ClassTag[T](cls))
--> ExpressionEncoder.serializer (序列化操作)
-->CreateNamedStruct.flatten(匹配到If的分支调用CreateNamedStruct.flatten)
-->Alias(v, n.toString)(起别名)
-->exprId = NamedExpression.newExprId(ExprId就是序列化的id)
--> ExprId(curId.getAndIncrement(), jvmId)(序列化的id最终生成)
代码流程如下截图:
下篇写写createOrReplaceTempView的运行原理~