spark sql逻辑计划(优化完)转物理计划
来源:互联网 发布:国内餐饮软件排名 编辑:程序博客网 时间:2024/04/30 13:21
在org.apache.spark.sql.execution中实现了有所有的数据库操作,但是注意这里仅仅是物理算子,这些操作分为三类:UnaryNode,LeafNode和BinaryNode。
一元节点UnaryNode的操作有:
Aggregate,DebugNode,EXchange,Filter,Generate,Project,Sample,Sort,StopAfter,TopK。
二元节点BinaryNode的操作有:
BroadcastNestedLoopJoin,CartesianProduct,SparkEquiInnerJoin。
叶子节点LeftNode的操作有:
ExistingRdd,ParquetTableScan。
分析一下join操作,join有两个孩子节点,是二元算子,其中会添加projection算子。有一种情况,比如T1表的a,b,c三个属性和T2表的a,d,e三个属性,如果在T1和T2表的a属性上做连接,最后输出三个属性T1.a,T1.b,T2.d。这样的话首先会在T1表上添加projection将a,b属性选出来,然后在T2表上添加Projection将a,d属性选出来,然后连接选出的属性,SparkEquiInnerJoin物理算子如下:
case class SparkEquiInnerJoin( leftKeys: Seq[Expression], rightKeys: Seq[Expression], left: SparkPlan,//左孩子,下面是右孩子 right: SparkPlan) extends BinaryNode { //outputPartitioning是基类中的函数,在此只是重载。partition策略如何 override def outputPartitioning: Partitioning = left.outputPartitioning //requiredChildDistribution是基类中的函数,在此是重载。孩子数据分布如何 override def requiredChildDistribution = ClusteredDistribution(leftKeys) :: ClusteredDistribution(rightKeys) :: Nil def output = left.output ++ right.output def execute() = attachTree(this, "execute") { val leftWithKeys = left.execute().mapPartitions { iter => //因为会有left孩子节点和leftWithKeys不一样的schema,所以要根据leftKeys做一次projection操作 val generateLeftKeys = new Projection(leftKeys, left.output) iter.map(row => (generateLeftKeys(row), row.copy())) } val rightWithKeys = right.execute().mapPartitions { iter => //因为会有left孩子节点和leftWithKeys不一样的schema,所以要根据leftKeys做一次projection操作 val generateRightKeys = new Projection(rightKeys, right.output) iter.map(row => (generateRightKeys(row), row.copy())) } // Do the join.做连接,连接左和右,得到所有的结果 val joined = filterNulls(leftWithKeys).joinLocally(filterNulls(rightWithKeys)) // Drop join keys and merge input tuples. // build每一行数据,就是简单的将生成的leftTuple和rightTuple相加 joined.map { case (_, (leftTuple, rightTuple)) => buildRow(leftTuple ++ rightTuple) } } /** * Filters any rows where the any of the join keys is null, ensuring three-valued * logic for the equi-join conditions. */ protected def filterNulls(rdd: RDD[(Row, Row)]) = rdd.filter { case (key: Seq[_], _) => !key.exists(_ == null) }}
在上面的join物理算子中execute函数式每个物理操作都必须实现的函数,还有两个函数outputPartitioning和requiredChildDistribution,这两个函数的作用呆会探讨。
- lazy val sparkPlan = planner(optimizedPlan).next()
- lazy val executedPlan: SparkPlan = prepareForExecution(sparkPlan)
上面这两步中第一步是从优化过的逻辑执行计划生成物理执行计划,在此调用的QueryPlanner抽象类中的apply方法,这个方法将逻辑执行计划中的每个操作对应strategies中相应的case class来生成具体的物理操作,现在strategies有这么多个,可以在SqlContext类中找到,如下:
/* * 所有的策略都在这里。 * */ val strategies: Seq[Strategy] = TopK :: PartialAggregation :: SparkEquiInnerJoin :: ParquetOperations :: BasicOperators :: CartesianProduct :: BroadcastNestedLoopJoin :: Nil
第二步会调用outputPartitioning和requiredChildDistribution这两个函数,是从两个child的分区策略和数据分布情况来确定是否需要添加shuffle操作,具体代码是在Exchange.scala中的AddExchange函数中,在此对物理执行计划分析看是否需要添加shuffle。
以上分析基于spark sql的从优化完的逻辑执行计划到物理执行计划的生成,总体来说分两方面,一方面是利用strategies讲逻辑算子转化为物理算子,还有一方面,因为是分布式系统,少不了的需要在物理执行计划中添加shuffle,接下来:
1,具体分析什么情况下需要添加AddExchange。
2,需要了解所有的物理操作算子,特别是join算子的变形。
本文完
- spark sql逻辑计划(优化完)转物理计划
- Spark SQL 物理执行计划各操作实现
- Spark SQL 物理执行计划各操作实现
- Spark源码--逻辑计划优化之表达式简化
- Spark SQL模块代码分析(查询语句到逻辑查询计划树的过程)
- Spark SQL系列------1. Spark SQL 物理计划的Shuffle实现
- Sql优化-执行计划
- spark中job的逻辑计划--RDD
- sql优化(1)-查看执行计划
- Catalyst 优化逻辑执行计划规则
- Pig源码分析: 逻辑执行计划优化
- Catalyst 优化逻辑执行计划规则
- SQL 执行计划 查询优化
- SQL查询执行计划优化
- Mysql SQL优化&执行计划
- Mysql SQL优化&执行计划
- Mysql SQL优化&执行计划
- Mysql SQL优化&执行计划
- 【黑马程序员】C#笔记之值类型和引用类型
- shell 关联数组添加元素问题
- 【Android-UI】包含多个子View时触发父节点的焦点事件
- 【日志】2014_4_7 琐碎杂事,无具体技术
- spring 上传文件
- spark sql逻辑计划(优化完)转物理计划
- Android自定义View全面总结
- 针对华为通讯模块USB设备 android、linux 上位机集成的一些经验
- Java 小程序:实现一个购物流程的功能(2)
- 并发不是并行 它更好!
- 如何用java语言实现遍历字符串中每个字符出现的次数
- hdu 3535 AreYouBusy dp
- 一个支持大数计算的类型 仅不支持除法
- emacs浏览器配置