首页 > 学院 > 开发设计 > 正文

spark core组件:RDD、DataFrame和DataSet介绍、场景与比较

2019-11-06 07:07:08
字体:
来源:转载
供稿:网友
spark生态系统中,Spark Core,包括各种Spark的各种核心组件,它们能够对内存和硬盘进行操作,或者调用CPU进行计算。spark core定义了RDD、DataFrame和DataSetspark最初只有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=7214DataFrame是什么?在Spark中,DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格。DataFrame与RDD的主要区别在于,前者带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。这使得Spark SQL得以洞察更多的结构信息,从而对藏于DataFrame背后的数据源以及作用于DataFrame之上的变换进行了针对性的优化,最终达到大幅提升运行时效率的目标。反观RDD,由于无从得知所存数据元素的具体内部结构,Spark Core只能在stage层面进行简单、通用的流水线优化。更多参考Spark SQL 1.3.0 DataFrame介绍、使用及提供了些完整的数据写入http://www.aboutyun.com/forum.php?mod=viewthread&tid=12358Spark 1.3.0版中 DataFrame 实践http://www.aboutyun.com/forum.php?mod=viewthread&tid=12312Spark 1.4为DataFrame新增的统计与数学函数http://www.aboutyun.com/forum.php?mod=viewthread&tid=13607DataSet是什么? Dataset是一个强类型的特定领域的对象,这种对象可以函数式或者关系操作并行地转换。每个Dataset也有一个被称为一个DataFrame的类型化视图,这种DataFrame是Row类型的Dataset,即Dataset[Row] Dataset是“懒惰”的,只在执行行动操作时触发计算。本质上,数据集表示一个逻辑计划,该计划描述了产生数据所需的计算。当执行行动操作时,Spark的查询优化程序优化逻辑计划,并生成一个高效的并行和分布式物理计划。更多参考:Spark 2.0中Dataset介绍和使用http://www.aboutyun.com/forum.php?mod=viewthread&tid=18780RDD和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映射为SparkSQl类型,然而RDD依赖于运行时反射机制。通过上面两点,DataSet的性能比RDD的要好很多DataFrame和DataSet比较Dataset可以认为是DataFrame的一个特例,主要区别是Dataset每一个record存储的是一个强类型值而不是一个Row。因此具有如下三个特点:1.DataSet可以在编译时检查类型2.是面向对象的编程接口。用Wordcount举例:[Scala] 纯文本查看 复制代码?
0102030405060708091011//DataFrame // Load a text file and interPRet each line as a java.lang.Stringvalds =sqlContext.read.text("/home/spark/1.6/lines").as[String]valresult =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] 纯文本查看 复制代码?
1234567//DataSet,完全使用scala编程,不要切换到DataFrame valwordCount =  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] 纯文本查看 复制代码?
12345678// select specific fields from the Dataset, apply a predicate// using the where() method, convert to an RDD, and show first 10// RDD rows valdeviceEventsDS =ds.select($"device_name", $"cca3", $"c02_level").where($"c02_level"> 1300)// convert to RDDs and take the first 10 rows valeventsRDD =deviceEventsDS.rdd.take(10)

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表