3. Spark SQL

3.1 Hive、Shark和Sparksql

Hive:Hadoop刚开始出来的时候,使用的是hadoop自带的分布式计算系统 MapReduce,但是MapReduce的使用难度较大,所以就开发了Hive。Hive的出现解决了MapReduce的使用难度较大的问题,Hive的运行原理是将HQL语句经过语法解析、逻辑计划、物理计划转化成MapReduce程序执行。

Shark:2011年Shark诞生,即Hive on Spark。为了实现与Hive兼容,Shark在HiveQL方面重用了Hive中HiveQL的解析、逻辑执行计划、执行计划优化等逻辑;可以近似认为仅将物理执行计划从MapReduce作业替换成了Spark作业,通过Hive 的HiveQL解析,把HiveQL翻译成Spark上的RDD操作;Shark的出现,使得SQL-on-Hadoop的性能比Hive有了10-100倍的提高。

Shark的缺陷

  1. 执行计划优化完全依赖于Hive,不方便添加新的优化策略

  2. 因为Spark是线程级并行,而MapReduce是进程级并行,因此,Spark在兼容 Hive的实现上存在线程安全问题,导致Shark不得不使用另外一套独立维护的打了补丁的Hive源码分支。

2014年7月,spark团队将Shark转给Hive进行管理,Hive on Spark是一个Hive的也就是说,Hive将不再受限于一个引擎,可以采用Map-Reduce、Tez、Spark等引擎;

Spark SQL作为Spark生态的一员诞生,不再受限于Hive,只是兼容Hive。

3.2 RDD和DataFrame、DataSet

RDD:弹性(Resilient)、分布式(Distributed)、数据集(Datasets),具有只读、Lazy、类型安全等特点,具有比较好用的API。RDD的劣势体现在性能限制上,它是一个JVM驻内存对象,这也就决定了存在GC的限制和数据增加时Java序列化成本的升高。

DataFrame:与RDD类似,DataFRame也是一个不可变的弹性分布式数据集。除了数据以外,还记录着数据的结构信息,即Schema。另外DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好。DataFrame的查询计划可以通过Spark catalyst optimiser进行优化,即使 Spark经验并不丰富,用dataframe写得程序也可以尽量被转化为高效的形式予以执行。

DataFrame只是知道字段,但是不知道字段的类型,所以在执行这些操作的时候是 没办法在编译的时候检查是否类型失败的。

上图直观地体现了 DataFrame 和 RDD 的区别。左侧的 RDD[Person]虽然以Person为类型参 数,但 Spark 框架本身不了解Person 类的内部结构。而右侧的DataFrame却提供了详细的结构信息,使得Spark SQL 可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。 DataFrame是为数据提供了Schema的视图。可以把它当做数据库中的一张表来对待,DataFrame也是懒执行的。性能上比 RDD 要高,主要原因:优化的执行计划:查询计划通过 Spark catalyst optimiser 进行优化。

DataSet:DataSet是DataFrame的扩展,是Spark最新的数据抽象。Dataframe 是 Dataset 的特列,DataFrame=Dataset[Row] ,所以可以通过 as 方法将 Dataframe 转换为 Dataset。Row 是一个类型,跟Car、Person 这些的类型一样,所有的表结构信息我都用 Row 来表示。DataSet 是强类型的。比如可以有 Dataset[Car],Dataset[Person]。DataFrame只是知道字段,但是不知道字段的类型,所以在执行这些操作的时候是没办法在编译的时候检查是否类型失败的,比如你可以对一个String进行减法操作,在执行的时候才报错,而DataSet不仅仅知道字段,而且知道字段类型,所以有更严格的错误检查。就跟JSON对象和类对象之间的类比。

3.2.1 三者的共性

  • 都是分布式弹性数据集,为处理超大型数据提供便利;
  • 都是Lasy的,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算,极端情况下,如果代码里面有创建、 转换,但是后面没有在Action中使用对应的结果,在执行时会被直接跳过;
  • 都有partition的概念;
  • 三者有许多共同的函数,如filter,排序等;
  • DataFrame和Dataset均可使用模式匹配获取各个字段的值和类型;
  • 三者可以相互转化

3.2.2 区别

RDD与DataFrame/DataSet的区别

RDD:

  • 用于Spark1.X各模块的API(SparkContext、MLLib,Dstream等)
  • 不支持sparksql操作
  • 不支持代码自动优化

DataFrame与DataSet:

  • 用于Spark2.X各模块的API(SparkSession、ML、StructuredStreaming等等)
  • 支持SparkSql操作,比如select,groupby之类,还能注册临时表/视窗,进行 sql语句操作
  • 支持一些方便的保存方式,比如保存成csv、json等格式
  • 基于sparksql引擎构建,支持代码自动优化

DataFrame与DataSet的区别

DataFrame:

  • DataFrame每一行的类型固定为Row,只有通过解析才能获取各个字段的值, 每一列的值没法直接访问。
  • DataFrame编译器缺少类型安全检查。
testDF.foreach{
line => val col1=line.getAs[String]("col1")
println(col1)
val col2=line.getAs[String]("col2")
println(col2)
}

DataSet:

  • DataFrame和DataSet之间,可以看成JSON对象和类对象之间的类比。
  • DataSet是类型安全的。

3.2.3 Sql、dataframe、DataSet的类型安全

  • 如果使用Spark SQL的查询语句,要直到运行时你才会发现有语法错误(这样做代价很大)。
  • 如果使用DataFrame,你在也就是说,当你在 DataFrame 中调用了 API 之外的函数时,编译器就可以发现这个错。但如果此时,使用了一个不存在字段的名字,则只能到运行时才能发现错误;
  • 如果用的是DataSet[Person],所有不匹配的类型参数都可以在编译时发现;

3.2.4 什么时候使用DataFrame或DataSet

下面的情况可以考虑使用DataFrame或Dataset,

  • 如果你需要丰富的语义、高级抽象和特定领域专用的 API,那就使用 DataFrame 或 Dataset;
  • 如果你的处理需要对半结构化数据进行高级处理,如 filter、map、aggregation、 average、sum、SQL 查询、列式访问或使用 lambda 函数,那就使用 DataFrame 或 Dataset;
  • 如果你想在编译时就有高度的类型安全,想要有类型的 JVM 对象,用上 Catalyst 优化,并得益于 Tungsten 生成的高效代码,那就使用 Dataset;
  • 如果你想在不同的 Spark 库之间使用一致和简化的 API,那就使用 DataFrame 或 Dataset;
  • 如果你是R或者Python使用者,就用DataFrame;

除此之外,在需要更细致的控制时就退回去使用RDD;

3.2.5 RDD、DataFrame、DataSet之间的转换

1. RDD转DataFrame、Dataset

  • RDD转DataFrame:一般用元组把一行的数据写在一起,然后在toDF中指定字段名。

  • RDD转Dataset:需要提前定义字段名和类型。

2. DataFrame转RDD、Dataset

  • DataFrame转RDD:直接转 val rdd = testDF.rdd
  • DataFrame转Dataset:需要提前定义case class,然后使用as方法。

3. Dataset转RDD、DataFrame

  • DataSet转RDD:直接转 val rdd = testDS.rdd
  • DataSet转DataFrame:直接转即可,spark会把case class封装成Row。

3.3 Spark SQL优化

Catalyst是spark sql的核心,是一套针对spark sql 语句执行过程中的查询优化框架。因此要理解spark sql的执行流程,理解Catalyst的工作流程是理解spark sql的关键。而说到Catalyst,就必须提到下面这张图了,这张图描述了spark sql执行的全流程。其中,中间四步为catalyst的工作流程。

参考:https://www.jianshu.com/p/0aa4b1caac2e

SQL语句首先通过Parser模块被解析为语法树,此棵树称为Unresolved Logical Plan;Unresolved Logical Plan通过Analyzer模块借助于Catalog中的表信息解析为Logical Plan;此时,Optimizer再通过各种基于规则的优化策略进行深入优化,得到Optimized Logical Plan;优化后的逻辑执行计划依然是逻辑的,并不能被Spark系统理解,此时需要将此逻辑执行计划转换为Physical Plan。

Spark常见的优化策略有下面几类:

  1. Combine Limits:合并Limit,就是将两个相邻的limit合为一个。
  2. Constant Folding:常量叠加
  • NullPropagation:空格处理
  • BooleanSimplification:布尔表达式简化
  • ConstantFolding:常量叠加
  • SimplifyFilters:Filter简化
  • LikeSimplification:like表达式简化。
  • SimplifyCasts:Cast简化
  • SimplifyCaseConversionExpressions:CASE大小写转化表达式简化
  1. Filter Pushdown Filter下推
  • CombineFilters Filter合并
  • PushPredicateThroughProject:通过Project下推
  • PushPredicateThroughJoin:通过Join下推
  • ColumnPruning:列剪枝

搜索『后端精进之路』并关注,立刻获取文章合集和面试攻略,还有价值数千元的面试大礼包等你拿。

Spark系列 - (3) Spark SQL的更多相关文章

  1. Spark系列—01 Spark集群的安装

    一.概述 关于Spark是什么.为什么学习Spark等等,在这就不说了,直接看这个:http://spark.apache.org, 我就直接说一下Spark的一些优势: 1.快 与Hadoop的Ma ...

  2. Spark系列—02 Spark程序牛刀小试

    一.执行第一个Spark程序 1.执行程序 我们执行一下Spark自带的一个例子,利用蒙特·卡罗算法求PI: 启动Spark集群后,可以在集群的任何一台机器上执行一下命令: /home/spark/s ...

  3. Spark SQL概念学习系列之Spark SQL的简介(一)

    Spark SQL提供在大数据上的SQL查询功能,类似于Shark在整个生态系统的角色,它们可以统称为SQL on Spark. 之前,Shark的查询编译和优化器依赖于Hive,使得Shark不得不 ...

  4. Spark SQL概念学习系列之Spark SQL概述

    很多人一个误区,Spark SQL重点不是在SQL啊,而是在结构化数据处理! Spark SQL结构化数据处理 概要: 01 Spark SQL概述 02 Spark SQL基本原理 03 Spark ...

  5. Spark入门实战系列--1.Spark及其生态圈简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .简介 1.1 Spark简介 年6月进入Apache成为孵化项目,8个月后成为Apache ...

  6. Spark系列-SparkSQL实战

    Spark系列-初体验(数据准备篇) Spark系列-核心概念 Spark系列-SparkSQL 之前系统的计算大部分都是基于Kettle + Hive的方式,但是因为最近数据暴涨,很多Job的执行时 ...

  7. Spark入门实战系列--3.Spark编程模型(上)--编程模型及SparkShell实战

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .Spark编程模型 1.1 术语定义 l应用程序(Application): 基于Spar ...

  8. Spark入门实战系列--7.Spark Streaming(上)--实时流计算Spark Streaming原理介绍

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .Spark Streaming简介 1.1 概述 Spark Streaming 是Spa ...

  9. Spark入门实战系列--8.Spark MLlib(上)--机器学习及SparkMLlib简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .机器学习概念 1.1 机器学习的定义 在维基百科上对机器学习提出以下几种定义: l“机器学 ...

  10. Spark系列之二——一个高效的分布式计算系统

    1.什么是Spark? Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用的并行计算框架,Spark基于map reduce算法实现的分布式计算,拥有H ...

随机推荐

  1. SSH(一)架包的引入

    一年多未使用了,有些东西真的会忘. 一.ssh的图形化记忆运作流程 二.Struts2.hibernate.spring需要引用的jar包 Struts2: 基本开发:struts-2.3.32\ap ...

  2. VMware宿主机访问虚拟机的Web服务

    VMware宿主机访问虚拟机的Web服务,主要就是宿主机可以通过IP能够访问到虚拟机. 可以尝试使用以下步骤. 1.关闭虚拟机,把网络连接方式修改成桥接方式. 2.打开虚拟机后,把虚拟机的防火墙关闭. ...

  3. 基于 RocketMQ 的 Dubbo-go 通信新范式

    本文作者:郝洪范 ,Dubbo-go Committer,京东资深研发工程师. 一.MQ Request Reply特性介绍 什么是 RPC 通信? 如上图所示,类似于本地调用,A 服务响应调用 B ...

  4. 【collection】1.java容器之HashMap&LinkedHashMap&Hashtable

    Map源码剖析 HashMap&LinkedHashMap&Hashtable hashMap默认的阈值是0.75 HashMap put操作 put操作涉及3种结构,普通node节点 ...

  5. Docker常用命令、Docker Compose、DockerFile实践

    〇.简介 https://hub.docker.com/ 1.架构 2.目录 镜像操作 容器操作 容器运行 Docker示例-MySQL Docker示例-Redis Docker示例-Nacos 使 ...

  6. 【大数据面试】【框架】Shuffle优化、内存参数配置、Yarn工作机制、调度器使用

    三.MapReduce 1.Shuffle及其优化☆ Shuffle是Map方法之后,Reduce方法之前,混洗的过程 Map-->getPartition(标记数据的分区)-->对应的环 ...

  7. Rust学习之旅(读书笔记):枚举 (Enum)

    Rust学习之旅(读书笔记):枚举 (Enum) C 语言的枚举类型很弱,不如后来的语言,也不如之前的语言.在 C 语言里面枚举量就是一个名字,更方便的定义常量.今天读了<The Rust Pr ...

  8. ORM数据库查询优化only与defer(select_related与prefetch_related)

    目录 一:数据库查询优化 1.ORM语句特点 2.only 3.defer 4.only与defer区别 5.select_related与prefetch_related 6.select_rela ...

  9. Mapper的动态代理

    可以自动生产接口的实现类 ,所以就不需要再写daoImpl这个实现类了, 直接使用sqlSession.getMapper自动生成实现类 @Before 此注解的目的是为了将@Befoe 作为首先执行 ...

  10. @Data加在子类上,子类无法获取父类的属性

    1.问题描述 我的子类继承父类,并在子类上加了@Data注解.但在程序运行时,输出的结果只有我在子类中定义的属性,父类的属性没有输出. 这是我定义的子类: 这个是子类继承的父类: 这个是输出结果: 可 ...