Spark SQL源码分析之核心流程

原创 2014年07月10日 18:11:01

    /** Spark SQL源码分析系列文章*/

    自从去年Spark Submit 2013 Michael Armbrust分享了他的Catalyst,到至今1年多了,Spark SQL的贡献者从几人到了几十人,而且发展速度异常迅猛,究其原因,个人认为有以下2点:

    1、整合:将SQL类型的查询语言整合到 Spark 的核心RDD概念里。这样可以应用于多种任务,流处理,批处理,包括机器学习里都可以引入Sql。
    2、效率:因为Shark受到hive的编程模型限制,无法再继续优化来适应Spark模型里。

    前一段时间测试过Shark,并且对Spark SQL也进行了一些测试,但是还是忍不住对Spark SQL一探究竟,就从源代码的角度来看一下Spark SQL的核心执行流程吧。

一、引子

先来看一段简单的Spark SQL程序:
1. val sqlContext = new org.apache.spark.sql.SQLContext(sc)
2. import sqlContext._
3.case class Person(name: String, age: Int)
4.val people = sc.textFile("examples/src/main/resources/people.txt").map(_.split(",")).map(p => Person(p(0), p(1).trim.toInt))
5.people.registerAsTable("people")
6.val teenagers = sql("SELECT name FROM people WHERE age >= 13 AND age <= 19")
7.teenagers.map(t => "Name: " + t(0)).collect().foreach(println)

程序前两句1和2生成SQLContext,导入sqlContext下面的all,也就是运行SparkSQL的上下文环境。
程序3,4两句是加载数据源注册table
第6句是真正的入口,是sql函数,传入一句sql,先会返回一个SchemaRDD。这一步是lazy的,直到第七句的collect这个action执行时,sql才会执行。


 二、SQLCOntext

SQLContext是执行SQL的上下文对象,首先来看一下它Hold的有哪些成员:

Catalog  

 一个存储<tableName,logicalPlan>的map结构,查找关系的目录,注册表,注销表,查询表和逻辑计划关系的类。


SqlParser 

 Parse 传入的sql来对语法分词,构建语法树,返回一个logical plan


Analyzer 

  logical plan的语法分析器


Optimizer 

 logical Plan的优化器


LogicalPlan 

逻辑计划,由catalyst的TreeNode组成,可以看到有3种语法树


SparkPlanner 

包含不同策略的优化策略来优化物理执行计划


QueryExecution 

sql执行的环境上下文


就是这些对象组成了Spark SQL的运行时,看起来很酷,有静态的metadata存储,有分析器、优化器、逻辑计划、物理计划、执行运行时。
那这些对象是怎么相互协作来执行sql语句的呢?

三、Spark SQL执行流程

话不多说,先上图,这个图我用一个在线作图工具process on话的,画的不好,图能达意就行:

      

核心组件都是绿色的方框,每一步流程的结果都是蓝色的框框,调用的方法是橙色的框框。

先概括一下,大致的执行流程是:
Parse SQL -> Analyze Logical Plan -> Optimize Logical Plan -> Generate Physical Plan -> Prepareed Spark Plan -> Execute SQL -> Generate RDD

更具体的执行流程:

     sql or hql -> sql parser(parse)生成 unresolved logical plan -> analyzer(analysis)生成analyzed logical plan  -> optimizer(optimize)optimized logical plan -> spark planner(use strategies to plan)生成physical plan -> 采用不同Strategies生成spark plan -> spark plan(prepare) prepared spark plan -> call toRDD(execute()函数调用) 执行sql生成RDD


3.1、Parse SQL

 回到开始的程序,我们调用sql函数,其实是SQLContext里的sql函数它的实现是new一个SchemaRDD,在生成的时候就调用parseSql方法了。
	  /**
   * Executes a SQL query using Spark, returning the result as a SchemaRDD.
   *
   * @group userf
   */
   def sql(sqlText: String): SchemaRDD = new SchemaRDD(this, parseSql(sqlText))
   结果是会生成一个逻辑计划
   @transient
  protected[sql] val parser = new catalyst.SqlParser  


  protected[sql] def parseSql(sql: String): LogicalPlan = parser(sql)

 3.2、Analyze to Execution

当我们调用SchemaRDD里面的collect方法时,则会初始化QueryExecution,开始启动执行。
 override def collect(): Array[Row] = queryExecution.executedPlan.executeCollect()
我们可以很清晰的看到执行步骤:

protected abstract class QueryExecution {
    def logical: LogicalPlan

    lazy val analyzed = analyzer(logical)  //首先分析器会分析逻辑计划
    lazy val optimizedPlan = optimizer(analyzed) //随后优化器去优化分析后的逻辑计划
    // TODO: Don't just pick the first one...
    lazy val sparkPlan = planner(optimizedPlan).next() //根据策略生成plan物理计划
    // executedPlan should not be used to initialize any SparkPlan. It should be
    // only used for execution.
    lazy val executedPlan: SparkPlan = prepareForExecution(sparkPlan) //最后生成已经准备好的Spark Plan

    /** Internal version of the RDD. Avoids copies and has no schema */
    lazy val toRdd: RDD[Row] = executedPlan.execute() //最后调用toRDD方法执行任务将结果转换为RDD

    protected def stringOrError[A](f: => A): String =
      try f.toString catch { case e: Throwable => e.toString }

    def simpleString: String = stringOrError(executedPlan)

    override def toString: String =
      s"""== Logical Plan ==
         |${stringOrError(analyzed)}
         |== Optimized Logical Plan ==
         |${stringOrError(optimizedPlan)}
         |== Physical Plan ==
         |${stringOrError(executedPlan)}
      """.stripMargin.trim
  }

至此整个流程结束。

  四、总结:

  通过分析SQLContext我们知道了Spark SQL都包含了哪些组件,SqlParser,Parser,Analyzer,Optimizer,LogicalPlan,SparkPlanner(包含Physical Plan),QueryExecution.
  通过调试代码,知道了Spark SQL的执行流程:
sql or hql -> sql parser(parse)生成 unresolved logical plan -> analyzer(analysis)生成analyzed logical plan  -> optimizer(optimize)optimized logical plan -> spark planner(use strategies to plan)生成physical plan -> 采用不同Strategies生成spark plan -> spark plan(prepare) prepared spark plan -> call toRDD(execute()函数调用) 执行sql生成RDD
  
  随后还会对里面的每个组件对象进行研究,看看catalyst究竟做了哪些优化。
  

  ——EOF——


原创文章,转载请注明:

转载自:OopsOutOfMemory盛利的Blog,作者: OopsOutOfMemory

本文链接地址:http://blog.csdn.net/oopsoom/article/details/37658021

注:本文基于署名-非商业性使用-禁止演绎 2.5 中国大陆(CC BY-NC-ND 2.5 CN)协议,欢迎转载、转发和评论,但是请保留本文作者署名和文章链接。如若需要用于商业目的或者与授权方面的协商,请联系我。

image



Spark修炼之道(进阶篇)——Spark入门到精通:第九节 Spark SQL运行流程解析

1.整体运行流程使用下列代码对SparkSQL流程进行分析,让大家明白LogicalPlan的几种状态,理解SparkSQL整体执行流程// sc is an existing SparkContex...
  • lovehuangjiaju
  • lovehuangjiaju
  • 2015年12月31日 10:58
  • 10010

Spark SQL核心类解析

一、执行计划实体相关      Tree是Catalyst执行计划表示的数据结构。LogicalPlans,Expressions和Pysical Operators都可以使用Tree来表示。T...
  • junerli
  • junerli
  • 2017年11月24日 14:15
  • 108

spark sql 执行流程

在前面的文章《spark基础(上篇)》和《spark基础(下篇)》里面已经介绍了spark的一些基础知识,知道了spark sql是spark中一个主要的框架之一。本文我们通过源码,来介绍下spark...
  • xuetaoxuetao
  • xuetaoxuetao
  • 2018年01月10日 16:44
  • 18

自定义SparkSql语法的一般步骤

SparkSql提供了对Hive的结构化查询语言,在某些业务场景下,我们可能需要对sql语法进行扩展,在此以自定义merge语法说明其一般步骤。         Hive中parquet格式表的数据文...
  • u012477420
  • u012477420
  • 2017年10月22日 13:03
  • 231

sparkSQL1.1入门之四:深入了解sparkSQL运行计划

前面两章花了不少篇幅介绍了SparkSQL的运行过程,很多读者还是觉得其中的概念很抽象,比如Unresolved LogicPlan、LogicPlan、PhysicalPlan是长得什么样子,没点印...
  • book_mmicky
  • book_mmicky
  • 2014年10月22日 08:59
  • 4792

《深入理解SPARK:核心思想与源码分析》(第1章)

在深入了解一个系统的原理、实现细节之前,应当先准备好它的源码编译环境、运行环境。如果能在实际环境安装和运行Spark,显然能够提升读者对于Spark的一些感受,对系统能有个大体的印象,有经验的技术人员...
  • beliefer
  • beliefer
  • 2016年01月15日 13:44
  • 14863

Spark一系列入门流程

本文的目的:利用Intellij Idea在windows搭建spark 开发环境 环境:windows 10, intellij idea2016.1.1, spark 1.6.2(HDP),ha...
  • dufufd
  • dufufd
  • 2017年05月03日 16:57
  • 253

Spark源码系列(九)Spark SQL初体验之解析过程详解

好久没更新博客了,之前学了一些R语言和机器学习的内容,做了一些笔记,之后也会放到博客上面来给大家共享。一个月前就打算更新Spark Sql的内容了,因为一些别的事情耽误了,今天就简单写点,Spark1...
  • qq_33813365
  • qq_33813365
  • 2017年04月23日 10:46
  • 261

《深入理解SPARK:核心思想与源码分析》(第1章)

在深入了解一个系统的原理、实现细节之前,应当先准备好它的源码编译环境、运行环境。如果能在实际环境安装和运行Spark,显然能够提升读者对于Spark的一些感受,对系统能有个大体的印象,有经验的技术人员...
  • beliefer
  • beliefer
  • 2016年01月15日 13:44
  • 14863

Spark SQL 初探: 使用大数据分析2000万数据

去年网上曾放出个2000W的开房记录的数据库, 不知真假。 最近在学习Spark, 所以特意从网上找来数据测试一下, 这是一个绝佳的大数据素材。 如果数据涉及到个人隐私,请尽快删除, 本站不提供此类数...
  • cq1982
  • cq1982
  • 2015年05月21日 16:37
  • 1951
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Spark SQL源码分析之核心流程
举报原因:
原因补充:

(最多只允许输入30个字)