Spark(十六)DataSet

2021年11月20日 阅读数:3
这篇文章主要向大家介绍Spark(十六)DataSet,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

 

Spark最吸引开发者的就是简单易用、跨语言(Scala, Java, Python, and R)的API。html

本文主要讲解Apache Spark 2.0中RDD,DataFrame和Dataset三种API;它们各自适合的使用场景;它们的性能和优化;列举使用DataFrame和DataSet代替RDD的场景。本文聚焦DataFrame和Dataset,由于这是Apache Spark 2.0的API统一的重点。数据库

Apache Spark 2.0统一API的主要动机是:简化Spark。经过减小用户学习的概念和提供结构化的数据进行处理。除告终构化,Spark也提供higher-level抽象和API做为特定领域语言(DSL)。apache

弹性数据集(RDD)编程

RDD是Spark创建之初的核心API。RDD是不可变分布式弹性数据集,在Spark集群中可跨节点分区,并提供分布式low-level API来操做RDD,包括transformation和action。安全

什么时候使用RDD?性能优化

使用RDD的通常场景:分布式

你须要使用low-level的transformation和action来控制你的数据集;函数式编程

你的数据集非结构化,好比:流媒体或者文本流;函数

你想使用函数式编程来操做你的数据,而不是用特定领域语言(DSL)表达;性能

你不想加入schema,好比,当经过名字或者列处理(或访问)数据属性不在乎列式存储格式;

当你能够放弃使用DataFrame和Dataset来优化结构化和半结构化数据集的时候。

在Spark2.0中RDD发生了什么

你可能会问:RDD是否是成为“二等公民”了?或者是否是干脆之后不用了?

答案固然是NO!

经过后面的描述你会得知:Spark用户能够在RDD,DataFrame和Dataset三种数据集之间无缝转换,并且只须要使用超级简单的API方法。

DataFrames

DataFrame与RDD相同之处,都是不可变分布式弹性数据集。不一样之处在于,DataFrame的数据集都是按指定列存储,即结构化数据。相似于传统数据库中的表。DataFrame的设计是为了让大数据处理起来更容易。DataFrame容许开发者把结构化数据集导入DataFrame,并作了higher-level的抽象;DataFrame提供特定领域的语言(DSL)API来操做你的数据集。

在Spark2.0中,DataFrame API将会和Dataset API合并,统一数据处理API。因为这个统一“有点急”,致使大部分Spark开发者对Dataset的high-level和type-safe API并无什么概念。

DataSets

从Spark2.0开始,DataSets扮演了两种不一样的角色:强类型API和弱类型API,见下表。从概念上来说,能够把DataFrame 看成一个泛型对象的集合DataSet[Row], Row是一个弱类型JVM 对象。相对应地,若是JVM对象是经过Scala的case class或者Java class来表示的,Dataset是强类型的。

Dataset API的优点

对于Spark开发者而言,你将从Spark 2.0的DataFrame和Dataset统一的API得到如下好处:

1. 静态类型和运行时类型安全

考虑静态类型和运行时类型安全,SQL有不多的限制而Dataset限制不少。例如,Spark SQL查询语句,你直到运行时才能发现语法错误(syntax error),代价较大。而后DataFrame和Dataset在编译时就可捕捉到错误,节约开发时间和成本。

Dataset API都是lambda函数和JVM typed object,任何typed-parameters不匹配即会在编译阶段报错。所以使用Dataset节约开发时间。

2. High-level抽象以及结构化和半结构化数据集的自定义视图

DataFrame是Dataset[Row]的集合,把结构化数据集视图转换成半结构化数据集。例如,有个海量IoT设备事件数据集,用JSON格式表示。JSON是一个半结构化数据格式,很适合使用Dataset, 转成强类型的Dataset[DeviceIoTData]。

使用Scala为JSON数据DeviceIoTData定义case class。

紧接着,从JSON文件读取数据

上面代码运行时底层会发生下面3件事。

Spark读取JSON文件,推断出其schema,建立一个DataFrame;

Spark把数据集转换DataFrame -> Dataset[Row],泛型Row object,由于这时还不知道其确切类型;

Spark进行转换:Dataset[Row] -> Dataset[DeviceIoTData],DeviceIoTData类的Scala JVM object

咱们的大多数人,在操做结构化数据时,都习惯于以列的方式查看和处理数据列,或者访问对象的指定列。Dataset 是Dataset[ElementType]类型对象的集合,既能够编译时类型安全,也能够为强类型的JVM对象定义视图。从上面代码获取到的数据能够很简单的展现出来,或者用高层方法处理。

3. 简单易用的API

虽然结构化数据会给Spark程序操做数据集带来挺多限制,但它却引进了丰富的语义和易用的特定领域语言。大部分计算能够被Dataset的high-level API所支持。例如,简单的操做agg,select,avg,map,filter或者groupBy便可访问DeviceIoTData类型的Dataset。

使用特定领域语言API进行计算是很是简单的。例如,使用filter()和map()建立另外一个Dataset。

把计算过程翻译成领域API比RDD的关系代数式表达式要容易的多。例如:

4. 性能和优化

使用DataFrame和Dataset API得到空间效率和性能优化的两个缘由:

首先:由于DataFrame和Dataset是在Spark SQL 引擎上构建的,它会使用Catalyst优化器来生成优化过的逻辑计划和物理查询计划。

R,Java,Scala或者Python的DataFrame/Dataset API,全部的关系型的查询都运行在相同的代码优化器下,代码优化器带来的的是空间和速度的提高。不一样的是Dataset[T]强类型API优化数据引擎任务,而弱类型API DataFrame在交互式分析场景上更快,更合适。

其次,经过博客https://databricks.com/blog/2016/05/23/apache-spark-as-a-compiler-joining-a-billion-rows-per-second-on-a-laptop.html 能够知道:Dataset能使用Encoder映射特定类型的JVM 对象到Tungsten内部内存表示。Tungsten的Encoder能够有效的序列化/反序列化JVM object,生成字节码来提升执行速度。

何时使用DataFrame或者Dataset?

你想使用丰富的语义,high-level抽象,和特定领域语言API,那你可使用DataFrame或者Dataset;

你处理的半结构化数据集须要high-level表达,filter,map,aggregation,average,sum,SQL查询,列式访问和使用lambda函数,那你可使用DataFrame或者Dataset;

想利用编译时高度的type-safety,Catalyst优化和Tungsten的code生成,那你可使用DataFrame或者Dataset;

你想统一和简化API使用跨Spark的Library,那你可使用DataFrame或者Dataset;

若是你是一个R使用者,那你可使用DataFrame或者Dataset;

若是你是一个Python使用者,那你可使用DataFrame或者Dataset。

你能够无缝地把DataFrame或者Dataset转化成一个RDD,只需简单的调用.rdd:

总结

经过上面的分析,什么状况选择RDD,DataFrame仍是Dataset已经很明显了。RDD适合须要low-level函数式编程和操做数据集的状况;DataFrame和Dataset适合结构化数据集,使用high-level和特定领域语言(DSL)编程,空间效率高和速度快。