Spark SQL 学习比较-1

ParallelCollectionRDD 到 DataFrame 生成步骤

  1. 通过 spark.sparkContext.parallelize(Seq) 创建 ParallelCollectionRDD
  2. 通过 implicit 方法 rddToDatasetHolder(),进入_sqlContext.createDataset(rdd)
  3. rdd被包装为 SerializeFromObject 对象(通过 ExternalRDD的apply()方法)
  • 通过 import sparkSession.implicits._ 可以自动帮我们引入非常多的spark内部自动转换
  • ExternalRDD 类层次结构: ExternalRDD --> LeafNode --> LogicalPlan
  • encoderFor[T] 方法 : 在SQLImplicits implicit 引入了ExpressionEncoder()对象(object.apply() 方法中反射类属性得到ExpressionEncoder对象),并通过 implicitly[Encoder[A]] 得到该实例对象
  • 通过CatalystSerde.generateObjAttr[T]反射获取RDD中对象的属性作为ExternalRDD的Attribute: AttributeReference('obj',T, nullable)
  • 通过Encoder中的Schema填充Seq[NamedExpression],生成SerializeFromObject对象, SerializeFromObject 类结构:SerializeFromObject --> ObjectConsumer --> UnaryNode --> LogicalPlan
  1. SerializeFromObject 被包装为 Dataset
  • 进入Dataset构造方法
  • 对上述 LogicalPlan对象封装 QueryExecution对象,
  • QueryExecution调用analyzed方法,分析内部的logicalPlan. sparkSession.sessionState.analyzer.executeAndCheck(logical)
  • 调用encoderFor(encoder),exprEnc.resolveAndBind(logicalPlan.output, sparkSession.sessionState.analyzer) 反射绑定Schema 信息,中间调用的 analyzer: Analyzer为 BaseSessionStateBuild内部对象
    返回 Dataset 实例
  1. 将 RDD 转换为 DatasetHolder 对象,再调用 toDF() 方法,toDF() 方法实际上还是在构建一个Dataset对象不过数据范型为[ROW],encoder=RowEncoder(schema)

createOrReplaceTempView 执行过程

  1. 创建LogicalPlan子类CreateViewCommand ,类层次关系:CreateViewCommand --> RunnableCommand --> Command --> LogicalPlan

  2. withPlan()方法内部使用使用上面的logicalPlan,调用Dataset.ofRows方法生成 Dataset 对象,实现过程和上面SerializeFromObject 被包装为 Dataset类似

    2.1 对logicalPlan封装为 QueryExecution

    2.2 analyze logicalPlan

    2.3 创建 Dataset 对象( 执行init方法 )

    2.4 Dataset.logicalPlan 对象实例化

     2.4.1 此时会先对传入的 queryExecution 进行 analyze
    
     2.4.2 如果结果为Command对象,会执行该Command
    

2.4.2 执行详细说明

  1. 执行Command方法说明
withAction("command", queryExecution)(_.executeCollect())

name: String : 命令名
qe: QueryExecution : 
action : 对SparkPlan进行转换的函数,实际上是调用对 qe.executedPlan 进行执行,并在执行对前后进行timeCostd等metrics进行统计
  1. Dataset.withAction() 方法内容
    SQLExecution.withNewExecutionId --> call --> action(qe.executedPlan)
  2. qe.executedPlan生成物理执行计划
  • lazy init executedPlan: SparkPlan = prepareForExecution(sparkPlan)
  • 使用物理计划生成规则,生成 exetutedPlan, AE 模式少了CollapseCodegenStages,ReuseExchange,多了 PlanQueryStage
// 普通优化器
	python.ExtractPythonUDFs,
	PlanSubqueries(sparkSession),
	EnsureRequirements(sparkSession.sessionState.conf),
	CollapseCodegenStages(sparkSession.sessionState.conf),
	ReuseExchange(sparkSession.sessionState.conf),
	ReuseSubquery(sparkSession.sessionState.conf)

// AE 优化器
	python.ExtractPythonUDFs,
	PlanSubqueries(sparkSession),
	EnsureRequirements(sparkSession.sessionState.conf),
	ReuseSubquery(sparkSession.sessionState.conf),
	// PlanQueryStage needs to be the last rule because it divides the plan into multiple sub-trees
	// by inserting leaf node QueryStageInput. Transforming the plan after applying this rule will
	// only transform node in a sub-tree.
	PlanQueryStage(sparkSession.sessionState.conf)
  1. 执行command(ExecutedCommandExec) executeCollect() 方法

    4.1 原始的 SparkPlan.executeCollect() 方法是调用collect() 方法得到byteArrayRdd,然后把结果收集到本地

    4.2 SubQueryExec实现: 启动一个线程,执行当前SparkPlan 并返回结果

    4.3 AE 的实现:QueryStage.executeCollect()

    • prepareExecuteStage()
      • 执行子任务
      • 优化器优化当前SparkPlan
      • codeGen and update the UI
    • child.executeCollect()

    4.4 在 ExecutedCommandExec.executeCollect() 方法被指向了 lazy变量 sideEffectResult,通过这个对象调用对应的 RunnableCommand.run() 方法,只执行一次,并缓存执行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值