在很多情况下,开发人员并不了解Scala 语言,也不了解Spark 常用的API ,但又非常想要使用Spark 框架提供的强大的数据分析能力。Spark 的开发工程师们考虑到了这个问题,于是利用SQL 语言的语法简洁、学习门槛低以及在编程语言中普及程度和流行程度高等诸多优势,开发了Spark SQL 模块。通过Spark SQL ,开发人员能够使用SQL 语句实现对结构化数据的处理。
本节主要介绍什么是Spark SQL、什么是DataFrame和什么是DataSat。
1. 什么是 Spark SQL
Spark SQL 是Spark 用于结构化数据(Structured Data )处理的Spark 模块。与基本的Spark RDD API 不同,Spark SQL 的抽象数据类型为Spark 提供了关于数据结构和正在执行的计算的更多信息。在内部,Spark SQL 使用这些额外的信息去做一些优化。
有多种方式与Spark SQL 进行交互,比如SQL 和Dataset API 。当计算结果的时候,这些接口使用相同的执行引擎,不依赖正在使用哪种API 或者语言。这种统一也就意味着开发者可以很容易在不同的API 之间进行切换,这些API 提供了最自然的方式来表达给定的转换。
Hive 是将Hive SQL 转换成MapReduce ,然后提交到集群上执行,大大简化了编写MapReduce 程序的复杂性,但是MapReduce 这种计算模型执行效率比较慢,所以Spark SQL 应运而生,它将Spark SQL 转换成RDD ,然后提交到集群上执行,执行效率非常高。
Spark SQL 提供了以下2 个编程抽象,类似Spark Core 中的RDD 。
-
DataFrame 。
-
DataSet 。
Spark SQL特点说明如下:
-
Integrated( 易整合 ) : Spark SQL 无缝地整合了 SQL 查询和 Spark 编程。
-
Uniform Data Access( 统一的数据访问方式 ) : Spark SQL 使用相同的方式连接不同的数据源。
-
Hive Integration( 集成 Hive) : Spark SQL 在已有的仓库上直接运行 SQL 或者 HiveQL 。
-
Standard Connectivity( 标准的连接方式 ) : Spark SQL 通过 JDBC 或者 ODBC 来连接。
2. 什么是DataFrame
与RDD 类似,DataFrame 也是一个分布式数据容器。
然而DataFrame 更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema 。
同时,DataFrame 与Hive 类似,也支持嵌套数据类型(struct 、array 和map )。
从API 易用性的角度上看,DataFrame API 提供的是一套高层的关系操作,比函数式的RDD API 要更加友好、门槛更低。
DataFrame 与RDD 的区别如下图 所示。
图中左侧的RDD[Person] 虽然以Person 为类型参数,但Spark 框架本身不了解Person 类的内部结构。而右侧的DataFrame 却提供了详细的结构信息,使得Spark SQL 可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。
DataFrame 为数据提供了schema 视图,可以把它当作数据库中的一张表来对待。
DataFrame 也是懒执行的,性能上比RDD 要高,主要原因在于优化的执行计划—查询计划通过Spark Catalyst Optimiser (Catalyst 优化器,基于Scala 的函数式编程结构设计的可扩展优化器)进行优化。
为了说明查询优化,我们来看下图 展示的数据分析的示例。
图中构造了两个DataFrame ,将它们join 之后又做了一次filter 操作。
如果原封不动地执行这个计划,最终的执行效率不是很高,因为join 是一个代价较大的操作,也可能会产生一个较大的数据集。如果我们能将filter 下推到join 下方,先对DataFrame 进行过滤,再join 过滤后的较小的结果集,便可以有效缩短执行时间。而Spark SQL 的查询优化器正是这样做的。简而言之,逻辑查询计划优化就是一个利用基于关系代数的等价变换,将高成本操作替换为低成本操作的过程。
3. 什么是DataSet
(1 )DataSet 是DataFrame API 的一个扩展,也是Spark SQL 最新的数据抽象(1.6 版本新增)。
(2 )用户友好的API 风格,既具有类型安全检查,也具有DataFrame 的查询优化特性。
(3 )Dataset 支持编解码器,当需要访问非堆上的数据时可以避免反序列化整个对象,提高了效率。
(4 )样例类被用来在DataSet 中定义数据的结构信息,样例类中每个属性的名称直接映射到DataSet 中的字段名称。
(5 )DataFrame 是DataSet 的特列,DataFrame=DataSet[Row] ,所以可以通过as 方法将DataFrame 转换为DataSet 。Row 是一个类型,跟Car 、Person 这些类型一样,所有的表结构信息都用Row 来表示。
(6 )DataSet 是强类型的,比如可以有DataSet[Car] 、DataSet[Person] 等。
(7 )DataFrame 只是知道字段,但是不知道字段的类型,所以在执行这些操作时是没办法在编译的时候检查字段类型是否正确,比如我们对一个字符串进行减法操作,在执行的时候才报错。而DataSet 不仅知道字段,还知道字段类型,所以有更严格的错误检查。
本文摘自《Spark 入门与大数据分析实战》,获出版社和作者授权发布。
