1.rdd,dataframe,dataset在哪个版本被引入?
2.什么情况下使用rdd,dataframe,dataset?
3.它们有什么不同?
spark生态系统中,Spark Core,包括各种Spark的各种核心组件,它们能够对内存和硬盘进行操作,或者调用CPU进行计算。
spark core定义了RDD、DataFrame和DataSet
spark最初只有RDD,DataFrame在Spark 1.3中被首次发布,DataSet在Spark1.6版本中被加入。
RDD是什么?
RDD:Spark的核心概念是RDD (resilientdistributed dataset),指的是一个只读的,可分区的分布式数据集,这个数据集的全部或部分可以缓存在内存中,在多次计算间重用。
更多内容推荐参考Spark RDD详解
http://www.aboutyun.com/forum.php?mod=viewthread&tid=7214
DataFrame是什么?
在Spark中,DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格。DataFrame与RDD的主要区别在于,前者带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。这使得Spark SQL得以洞察更多的结构信息,从而对藏于DataFrame背后的数据源以及作用于DataFrame之上的变换进行了针对性的优化,最终达到大幅提升运行时效率的目标。反观RDD,由于无从得知所存数据元素的具体内部结构,Spark Core只能在stage层面进行简单、通用的流水线优化。
更多参考
Spark SQL 1.3.0 DataFrame介绍、使用及提供了些完整的数据写入
Spark 1.3.0版中 DataFrame 实践
Spark 1.4为DataFrame新增的统计与数学函数
DataSet是什么?
Dataset是一个强类型的特定领域的对象,这种对象可以函数式或者关系操作并行地转换。每个Dataset也有一个被称为一个DataFrame的类型化视图,这种DataFrame是Row类型的Dataset,即Dataset[Row]
Dataset是“懒惰”的,只在执行行动操作时触发计算。本质上,数据集表示一个逻辑计划,该计划描述了产生数据所需的计算。当执行行动操作时,Spark的查询优化程序优化逻辑计划,并生成一个高效的并行和分布式物理计划。
更多参考:
Spark 2.0中Dataset介绍和使用
http://www.aboutyun.com/forum.php?mod=viewthread&tid=18780
RDD和DataFrame比较
DataFrame与RDD相同之处,都是不可变分布式弹性数据集。不同之处在于,DataFrame的数据集都是按指定列存储,即结构化数据。类似于传统数据库中的表。 DataFrame的设计是为了让大数据处理起来更容易。DataFrame允许开发者把结构化数据集导入DataFrame,并做了higher-level的抽象; DataFrame提供特定领域的语言(DSL)API来操作你的数据集。
上图直观地体现了DataFrame和RDD的区别。左侧的RDD[Person]虽然以Person为类型参数,但Spark框架本身不了解Person类的内部结构。而右侧的DataFrame却提供了详细的结构信息,使得Spark SQL可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。DataFrame多了数据的结构信息,即schema。RDD是分布式的Java对象的集合。DataFrame是分布式的Row对象的集合。DataFrame除了提供了比RDD更丰富的算子以外,更重要的特点是提升执行效率、减少数据读取以及执行计划的优化,比如filter下推、裁剪等。
提升执行效率
RDD API是函数式的,强调不变性,在大部分场景下倾向于创建新对象而不是修改老对象。这一特点虽然带来了干净整洁的API,却也使得Spark应用程序在运行期倾向于创建大量临时对象,对GC造成压力。在现有RDD API的基础之上,我们固然可以利用mapPartitions方法来重载RDD单个分片内的数据创建方式,用复用可变对象的方式来减小对象分配和GC的开销,但这牺牲了代码的可读性,而且要求开发者对Spark运行时机制有一定的了解,门槛较高。另一方面,Spark SQL在框架内部已经在各种可能的情况下尽量重用对象,这样做虽然在内部会打破了不变性,但在将数据返回给用户时,还会重新转为不可变数据。利用 DataFrame API进行开发,可以免费地享受到这些优化效果。
减少数据读取
分析大数据,最快的方法就是 ——忽略它。这里的“忽略”并不是熟视无睹,而是根据查询条件进行恰当的剪枝。
上文讨论分区表时提到的分区剪 枝便是其中一种——当查询的过滤条件中涉及到分区列时,我们可以根据查询条件剪掉肯定不包含目标数据的分区目录,从而减少IO。
对于一些“智能”数据格 式,Spark SQL还可以根据数据文件中附带的统计信息来进行剪枝。简单来说,在这类数据格式中,数据是分段保存的,每段数据都带有最大值、最小值、null值数量等 一些基本的统计信息。当统计信息表名某一数据段肯定不包括符合查询条件的目标数据时,该数据段就可以直接跳过(例如某整数列a某段的最大值为100,而查询条件要求a > 200)。
此外,Spark SQL也可以充分利用RCFile、ORC、Parquet等列式存储格式的优势,仅扫描查询真正涉及的列,忽略其余列的数据。
执行优化
人口数据分析示例
为了说明查询优化,我们来看上图展示的人口数据分析的示例。图中构造了两个DataFrame,将它们join之后又做了一次filter操作。如果原封不动地执行这个执行计划,最终的执行效率是不高的。因为join是一个代价较大的操作,也可能会产生一个较大的数据集。如果我们能将filter下推到 join下方,先对DataFrame进行过滤,再join过滤后的较小的结果集,便可以有效缩短执行时间。而Spark SQL的查询优化器正是这样做的。简而言之,逻辑查询计划优化就是一个利用基于关系代数的等价变换,将高成本的操作替换为低成本操作的过程。
得到的优化执行计划在转换成物 理执行计划的过程中,还可以根据具体的数据源的特性将过滤条件下推至数据源内。最右侧的物理执行计划中Filter之所以消失不见,就是因为溶入了用于执行最终的读取操作的表扫描节点内。
对于普通开发者而言,查询优化 器的意义在于,即便是经验并不丰富的程序员写出的次优的查询,也可以被尽量转换为高效的形式予以执行。
RDD和DataSet比较
DataSet以Catalyst逻辑执行计划表示,并且数据以编码的二进制形式被存储,不需要反序列化就可以执行sorting、shuffle等操作。
DataSet创立需要一个显式的Encoder,把对象序列化为二进制,可以把对象的scheme映射为Spark
SQl类型,然而RDD依赖于运行时反射机制。
通过上面两点,DataSet的性能比RDD的要好很多
DataFrame和DataSet比较
Dataset可以认为是DataFrame的一个特例,主要区别是Dataset每一个record存储的是一个强类型值而不是一个Row。因此具有如下三个特点:
1.DataSet可以在编译时检查类型
2.是面向对象的编程接口。用wordcount举例:
[Scala]
01
02
03
04
05
06
07
08
09
10
11
|
//DataFrame // Load a text file and interpret each line as a java.lang.String val ds = sqlContext.read.text( "/home/spark/1.6/lines" ).as[String] val result = ds .flatMap( _ .split( " " )) // Split on whitespace .filter( _ ! = "" ) // Filter empty words .toDF() // Convert to DataFrame to perform aggregation / sorting .groupBy($ "value" ) // Count number of occurences of each word .agg(count( "*" ) as "numOccurances" ) .orderBy($ "numOccurances" desc) // Show most common words first |
[Scala]
1
2
3
4
5
6
7
|
//DataSet,完全使用scala编程,不要切换到DataFrame val wordCount = ds.flatMap( _ .split( " " )) .filter( _ ! = "" ) .groupBy( _ .toLowerCase()) // Instead of grouping on a column expression (i.e. $"value") we pass a lambda function .count() |
3.后面版本DataFrame会继承DataSet,DataFrame是面向Spark SQL的接口。
DataFrame和DataSet可以相互转化,df.as[ElementType]这样可以把DataFrame转化为DataSet,ds.toDF()这样可以把DataSet转化为DataFrame。
场景
什么时候用RDD?
使用RDD的一般场景:
你需要使用low-level的transformation和action来控制你的数据集;
你得数据集非结构化,比如,流媒体或者文本流;
你想使用函数式编程来操作你得数据,而不是用特定领域语言(DSL)表达;
你不在乎schema,比如,当通过名字或者列处理(或访问)数据属性不在意列式存储格式;
你放弃使用DataFrame和Dataset来优化结构化和半结构化数据集
RDD在Apache Spark 2.0中惨遭抛弃?
答案当然是 NO !
通过后面的描述你会得知:Spark用户可以在RDD,DataFrame和Dataset三种数据集之间无缝转换,而是只需使用超级简单的API方法。
什么时候使用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:
[Scala]
1
2
3
4
5
6
7
8
|
// select specific fields from the Dataset, apply a predicate // using the where() method, convert to an RDD, and show first 10 // RDD rows val deviceEventsDS = ds.select($ "device_name" , $ "cca3" , $ "c02_level" ).where($ "c02_level" > 1300 ) // convert to RDDs and take the first 10 rows val eventsRDD = deviceEventsDS.rdd.take( 10 ) |