32.Spark RDD、DataFrame、DataSet区别和联系
1.简介


- 在Spark中,DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格。DataFrame与RDD的主要区别在于,前者带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。这使得Spark SQL得以洞察更多的结构信息,从而对藏于DataFrame背后的数据源以及作用于DataFrame之上的变换进行了针对性的优化,最终达到大幅提升运行时效率的目标。反观RDD,由于无从得知所存数据元素的具体内部结构,Spark Core只能在stage层面进行简单、通用的流水线优化。
- 左侧的RDD[Person]虽然以Person为类型参数,但Spark框架本身不了解Person类的内部结构。而右侧的DataFrame却提供了详细的结构信息,使得Spark SQL可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。DataFrame多了数据的结构信息,即schema。RDD是分布式的Java对象的集合。DataFrame是分布式的Row对象的集合。DataFrame除了提供了比RDD更丰富的算子以外,更重要的特点是提升执行效率、减少数据读取以及执行计划的优化,比如filter下推、裁剪等。
2.RDD
- 优点:
- -编译时类型安全
- 编译时就能检查出类型错误
- -面向对象的编程风格
- 直接通过类名点的方式来操作数据
- 缺点:
- -序列化和反序列化的性能开销
- 无论是集群间的通信, 还是IO操作都需要对对象的结构和数据进行序列化和反序列化.
- -GC的性能开销
- 频繁的创建和销毁对象, 势必会增加GC
3.DataFrame
DataFrame引入了schema和off-heap
schema : RDD每一行的数据, 结构都是一样的,这个结构就存储在schema中。 Spark通过schema就能够读懂数据, 因此在通信和IO时就只需要序列化和反序列化数据, 而结构的部分就可以省略了。
off-heap : 意味着JVM堆以外的内存, 这些内存直接受操作系统管理(而不是JVM)。Spark能够以二进制的形式序列化数据(不包括结构)到off-heap中, 当要操作数据时,就直接操作off-heap内存。由于Spark理解schema,所以知道该如何操作。
off-heap就像地盘,schema就像地图,Spark有地图又有自己地盘了,就可以自己说了算了,不再受JVM的限制,也就不再收GC的困扰了。
通过schema和off-heap,DataFrame解决了RDD的缺点,但是却丢了RDD的优点。DataFrame不是类型安全的,API也不是面向对象风格的。
- 创建DataFrame
在Spark SQL中,开发者可以非常便捷地将各种内、外部的单机、分布式数据转换为DataFrame。以下Python示例代码充分体现了Spark SQL 1.3.0中DataFrame数据源的丰富多样和简单易用:
# 从Hive中的users表构造DataFrame  
users = sqlContext.table("users")  
  
# 加载S3上的JSON文件  
logs = sqlContext.load("s3n://path/to/data.json", "json")  
  
# 加载HDFS上的Parquet文件  
clicks = sqlContext.load("hdfs://path/to/data.parquet", "parquet")  
  
# 通过JDBC访问MySQL  
comments = sqlContext.jdbc("jdbc:mysql://localhost/comments", "user")  
  
# 将普通RDD转变为DataFrame  
rdd = sparkContext.textFile("article.txt") \  
                  .flatMap(lambda line: line.split()) \  
                  .map(lambda word: (word, 1)) \  
                  .reduceByKey(lambda a, b: a + b) \  
wordCounts = sqlContext.createDataFrame(rdd, ["word", "count"])  
  
# 将本地数据容器转变为DataFrame  
data = [("Alice", 21), ("Bob", 24)]  
people = sqlContext.createDataFrame(data, ["name", "age"])  
  
# 将Pandas DataFrame转变为Spark DataFrame(Python API特有功能)  
sparkDF = sqlContext.createDataFrame(pandasDF)  
可见,从Hive表,到外部数据源API支持的各种数据源(JSON、Parquet、JDBC),再到RDD乃至各种本地数据集,都可以被方便快捷地加载、转换为DataFrame。这些功能也同样存在于Spark SQL的Scala API和Java API中。
- 使用DataFrame
和R、Pandas类似,Spark DataFrame也提供了一整套用于操纵数据的DSL。这些DSL在语义上与SQL关系查询非常相近(这也是Spark SQL能够为DataFrame提供无缝支持的重要原因之一)。以下是一组用户数据分析示例:
# 创建一个只包含"年轻"用户的DataFrame  
young = users.filter(users.age < 21)  
  
# 也可以使用Pandas风格的语法  
young = users[users.age < 21]  
  
# 将所有人的年龄加1  
young.select(young.name, young.age + 1)  
  
# 统计年轻用户中各性别人数  
young.groupBy("gender").count()  
  
# 将所有年轻用户与另一个名为logs的DataFrame联接起来  
young.join(logs, logs.userId == users.userId, "left_outer")  
除DSL以外,我们当然也可以像以往一样,用SQL来处理DataFrame:
young.registerTempTable("young")  
sqlContext.sql("SELECT count(*) FROM young")  
最后,当数据分析逻辑编写完毕后,我们便可以将最终结果保存下来或展现出来:
# 追加至HDFS上的Parquet文件  
young.save(path="hdfs://path/to/data.parquet",  
           source="parquet",  
           mode="append")  
  
# 覆写S3上的JSON文件  
young.save(path="s3n://path/to/data.json",  
           source="json",  
           mode="append")  
  
# 保存为SQL表  
young.saveAsTable(tableName="young", source="parquet" mode="overwrite")  
  
# 转换为Pandas DataFrame(Python API特有功能)  
pandasDF = young.toPandas()  
  
# 以表格形式打印输出  
young.show()  
4.DataSet
DataSet结合了RDD和DataFrame的优点,并带来的一个新的概念Encoder。
当序列化数据时,Encoder产生字节码与off-heap进行交互,能够达到按需访问数据的效果,而不用反序列化整个对象。Spark还没有提供自定义Encoder的API,但是未来会加入。
5.区别与联系
- RDD和DataSet
- DataSet以Catalyst逻辑执行计划表示,并且数据以编码的二进制形式被存储,不需要反序列化就可以执行sorting、shuffle等操作。
- DataSet创立需要一个显式的Encoder,把对象序列化为二进制,可以把对象的scheme映射为Spark SQL类型,然而RDD依赖于运行时反射机制。
- DataSet比RDD性能要好很多。
- DataFrame和DataSet
- Dataset可以认为是DataFrame的一个特例,主要区别是Dataset每一个record存储的是一个强类型值而不是一个Row。因此具有如下三个特点:
- DataSet可以在编译时检查类型
- DataSet是面向对象的编程接口。
- 后面版本DataFrame会继承DataSet,DataFrame是面向Spark SQL的接口。
- DataFrame和DataSet可以相互转化,df.as[ElementType]这样可以把DataFrame转化为DataSet,ds.toDF()这样可以把DataSet转化为DataFrame。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号