在spark中,RDD、DataFrame、Dataset是最常用的数据类型,本博文给出笔者在使用的过程中体会到的区别和各自的优势

共性:

1、RDD、DataFrame、Dataset全都是spark平台下的分布式弹性数据集,为处理超大型数据提供便利

2、三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算,极端情况下,如果代码里面有创建、转换,但是后面没有在Action中使用对应的结果,在执行时会被直接跳过,如

val sparkconf = new SparkConf().setMaster("local").setAppName("test").set("spark.port.maxRetries","1000")
val spark = SparkSession.builder().config(sparkconf).getOrCreate()
val rdd=spark.sparkContext.parallelize(Seq(("a", 1), ("b", 1), ("a", 1))) rdd.map{line=>
println("运行")
line._1
}

map中的println("运行")并不会运行

3、三者都会根据spark的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出

4、三者都有partition的概念,如

 var predata=data.repartition(24).mapPartitions{
PartLine => {
PartLine.map{
line =>
println(“转换操作”)
}
}
}

这样对每一个分区进行操作时,就跟在操作数组一样,不但数据量比较小,而且可以方便的将map中的运算结果拿出来,如果直接用map,map中对外面的操作是无效的,如

val rdd=spark.sparkContext.parallelize(Seq(("a", 1), ("b", 1), ("a", 1)))
var flag=0
val test=rdd.map{line=>
println("运行")
flag+=1
println(flag)
line._1
}
println(test.count)
println(flag)
/**
运行
1
运行
2
运行
3
3
0
* */

不使用partition时,对map之外的操作无法对map之外的变量造成影响

5、三者有许多共同的函数,如filter,排序等

6、在对DataFrame和Dataset进行操作许多操作都需要这个包进行支持

import spark.implicits._
//这里的spark是SparkSession的变量名

7、DataFrame和Dataset均可使用模式匹配获取各个字段的值和类型

DataFrame:

testDF.map{
case Row(col1:String,col2:Int)=>
println(col1);println(col2)
col1
case _=>
""
}

为了提高稳健性,最好后面有一个_通配操作,这里提供了DataFrame一个解析字段的方法

Dataset:

case class Coltest(col1:String,col2:Int)extends Serializable //定义字段名和类型
testDS.map{
case Coltest(col1:String,col2:Int)=>
println(col1);println(col2)
col1
case _=>
""
}

  

区别:

RDD:

1、RDD一般和spark mlib同时使用

2、RDD不支持sparksql操作

DataFrame:

1、与RDD和Dataset不同,DataFrame每一行的类型固定为Row,只有通过解析才能获取各个字段的值,如

testDF.foreach{
line =>
val col1=line.getAs[String]("col1")
val col2=line.getAs[String]("col2")
}

每一列的值没法直接访问

2、DataFrame与Dataset一般与spark ml同时使用

3、DataFrame与Dataset均支持sparksql的操作,比如select,groupby之类,还能注册临时表/视窗,进行sql语句操作,如

dataDF.createOrReplaceTempView("tmp")
spark.sql("select ROW,DATE from tmp where DATE is not null order by DATE").show(100,false)

4、DataFrame与Dataset支持一些特别方便的保存方式,比如保存成csv,可以带上表头,这样每一列的字段名一目了然

//保存
val saveoptions = Map("header" -> "true", "delimiter" -> "\t", "path" -> "hdfs://172.xx.xx.xx:9000/test")
datawDF.write.format("com.databricks.spark.csv").mode(SaveMode.Overwrite).options(saveoptions).save()
//读取
val options = Map("header" -> "true", "delimiter" -> "\t", "path" -> "hdfs://172.xx.xx.xx:9000/test")
val datarDF= spark.read.options(options).format("com.databricks.spark.csv").load()

利用这样的保存方式,可以方便的获得字段名和列的对应,而且分隔符(delimiter)可以自由指定

Dataset:

这里主要对比Dataset和DataFrame,因为Dataset和DataFrame拥有完全相同的成员函数,区别只是每一行的数据类型不同

DataFrame也可以叫Dataset[Row],每一行的类型是Row,不解析,每一行究竟有哪些字段,各个字段又是什么类型都无从得知,只能用上面提到的getAS方法或者共性中的第七条提到的模式匹配拿出特定字段

而Dataset中,每一行是什么类型是不一定的,在自定义了case class之后可以很自由的获得每一行的信息

case class Coltest(col1:String,col2:Int)extends Serializable //定义字段名和类型
/**
rdd
("a", 1)
("b", 1)
("a", 1)
* */
val test: Dataset[Coltest]=rdd.map{line=>
Coltest(line._1,line._2)
}.toDS
test.map{
line=>
println(line.col1)
println(line.col2)
}

可以看出,Dataset在需要访问列中的某个字段时是非常方便的,然而,如果要写一些适配性很强的函数时,如果使用Dataset,行的类型又不确定,可能是各种case class,无法实现适配,这时候用DataFrame即Dataset[Row]就能比较好的解决问题

转化:

RDD、DataFrame、Dataset三者有许多共性,有各自适用的场景常常需要在三者之间转换

DataFrame/Dataset转RDD:

这个转换很简单

val rdd1=testDF.rdd
val rdd2=testDS.rdd

RDD转DataFrame:

import spark.implicits._
val testDF = rdd.map {line=>
(line._1,line._2)
}.toDF("col1","col2")

一般用元组把一行的数据写在一起,然后在toDF中指定字段名

RDD转Dataset:

import spark.implicits._
case class Coltest(col1:String,col2:Int)extends Serializable //定义字段名和类型
val testDS = rdd.map {line=>
Coltest(line._1,line._2)
}.toDS

可以注意到,定义每一行的类型(case class)时,已经给出了字段名和类型,后面只要往case class里面添加值即可

Dataset转DataFrame:

这个也很简单,因为只是把case class封装成Row

import spark.implicits._
val testDF = testDS.toDF

DataFrame转Dataset:

import spark.implicits._
case class Coltest(col1:String,col2:Int)extends Serializable //定义字段名和类型
val testDS = testDF.as[Coltest]

这种方法就是在给出每一列的类型后,使用as方法,转成Dataset,这在数据类型是DataFrame又需要针对各个字段处理时极为方便

特别注意:

在使用一些特殊的操作时,一定要加上 import spark.implicits._ 不然toDF、toDS无法使用

谈谈RDD、DataFrame、Dataset的区别和各自的优势的更多相关文章

  1. sparkSQL中RDD——DataFrame——DataSet的区别

    spark中RDD.DataFrame.DataSet都是spark的数据集合抽象,RDD针对的是一个个对象,但是DF与DS中针对的是一个个Row RDD 优点: 编译时类型安全 编译时就能检查出类型 ...

  2. spark的数据结构 RDD——DataFrame——DataSet区别

    转载自:http://blog.csdn.net/wo334499/article/details/51689549 RDD 优点: 编译时类型安全 编译时就能检查出类型错误 面向对象的编程风格 直接 ...

  3. APACHE SPARK 2.0 API IMPROVEMENTS: RDD, DATAFRAME, DATASET AND SQL

    What’s New, What’s Changed and How to get Started. Are you ready for Apache Spark 2.0? If you are ju ...

  4. spark rdd df dataset

    RDD.DataFrame.DataSet的区别和联系 共性: 1)都是spark中得弹性分布式数据集,轻量级 2)都是惰性机制,延迟计算 3)根据内存情况,自动缓存,加快计算速度 4)都有parti ...

  5. RDD, DataFrame or Dataset

    总结: 1.RDD是一个Java对象的集合.RDD的优点是更面向对象,代码更容易理解.但在需要在集群中传输数据时需要为每个对象保留数据及结构信息,这会导致数据的冗余,同时这会导致大量的GC. 2.Da ...

  6. RDD、DataFrame和DataSet的区别

    原文链接:http://www.jianshu.com/p/c0181667daa0 RDD.DataFrame和DataSet是容易产生混淆的概念,必须对其相互之间对比,才可以知道其中异同. RDD ...

  7. Spark RDD、DataFrame和DataSet的区别

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   转载请标明出处:小帆的帆的专栏 RDD 优点: 编译时类型安全 编译时就能检查出类型错误 面向对象的编程风格 直接通过类 ...

  8. Spark入门之DataFrame/DataSet

    目录 Part I. Gentle Overview of Big Data and Spark Overview 1.基本架构 2.基本概念 3.例子(可跳过) Spark工具箱 1.Dataset ...

  9. Data Base sqlServer DataReader与DataSet的区别

    sqlServer   DataReader与DataSet的区别 从以下这几个方面比较: 1.与数据库连接: DataReader:面向连接,只读,只进,只能向前读,读完数据就断开连接: DataS ...

随机推荐

  1. For循环及例题

    For循环    (1)循环操作某一个功能(执行某段代码)    (2)四要素                  循环初始值                  循环条件                 ...

  2. 参加光环国际PRINCE2培训

    挑战埃及是全球首套能够同时适配PRINCE2认证人群,PMP认证人群的项目管理沙盘演练游戏.沙盘通过使用乐高积木作为道具,通过一场互动性极强的情景模拟为全球项目经理还原了四千年前古埃及金字塔建造的情景 ...

  3. [C++]STL容器Vector的内存释放

    直接抛出两句话,说明到底应该如何释放Vector占用的内存. “vector的clear不影响capacity,你应该swap一个空的vector.” <Effective STL>中的“ ...

  4. js 操作属性

    操作属性: 对象.setAttribute('属性名','值'); - 添加属性 对象.getAttribute('属性名'); - 获取属性值,如无此属性,那么返回null 对象.removeAtt ...

  5. Java实现缓存(LRU,FIFO)

    现在软件或者网页的并发量越来越大了,大量请求直接操作数据库会对数据库造成很大的压力,处理大量连接和请求就会需要很长时间,但是实际中百分之80的数据是很少更改的,这样就可以引入缓存来进行读取,减少数据库 ...

  6. 老李分享:持续集成学好jenkins之Git和Maven配置 2

    8.检查代码更新并编译 可以通过Poll SCM来设置定时检查编译功能 比如*/5 * * * * 就是每隔5分钟检查一次,如果git仓库中有更新,则执行build操作. 9.使用Maven私服加快下 ...

  7. 老李分享: 并行计算基础&编程模型与工具 2

    2.并行编程模型和工具 – MPI – MPI(Message Passing Interface)是一种消息传递编程模型,服务于进程通信.它不特指某一个对它的实现,而是一种标准和规范的代表,它是一种 ...

  8. (转)POPTEST创始人李爱然:谢谢,帮助我的朋友!!!!

    2015年11月15日,脉脉上随意浏览信息.每天有很多人加我,我也会主动加一些人.脉脉的广告语“打通职场人脉”,很直白的告诉我们脉脉是用来找人办事的.简单明了,不用故作清高. “利”,有利可图便是“友 ...

  9. Oracle常见错误集锦

    1.ORA-12560:TNS:协议适配器错误 OracleService<SID>服务没有启动 2. ORA-12541:TNS:无监听程序 Oracle<ORACLE_HOME& ...

  10. dotnet Core 调用HTTP接口,系统大量CLOSE_WAIT连接问题的分析,尚未解决。

    环境: dotnet core 1.0.1 CentOS 7.2 今天在服务器巡检的时候,发现一个服务大量抛出异常 异常信息为: LockStatusPushError&&Messag ...