1、转化原理
RDD关心数据,DataFrame包含结构信息,关心结构,DataSet包含结构和类型信息,关心类型;
① 将RDD转换为DataFrame,需要增加结构信息,所以调用toDF方法,需要增加结构;
② 将RDD转换为DataSet,需要增加结构和类型信息,所以需要转换为指定类型后,调用toDS方法;
③ 将DataFrame转换为DataSet时,因为已经包含结构信息,只有增加类型信息就可以,所以调用as[类型]
④因为DF中本身包含数据,所以转换为RDD时,直接调用rdd即可;
⑤因为DS中本身包含数据,所以转换为RDD时,直接调用rdd即可;
⑥因为DS本身包含数据结构信息,所以转换为DF时,直接调用toDF即可
2、Rdd->Dataset->Rdd转换案例
case class AbtestActionLogsModel(atype: String, domain: String,
platform: String, version: String, action_big_id: String,
action_small_id: String, action_id: String, txid: String,
memo: String, location_id: String, msg: String, uid: String, url: String,
uniqueid: String, projectid: String, planid: String, logType: String, var memoParam: String, var description: String, var memoValue: String) extends Serializable {
}
object AbtestActionMemo {
def main(args: Array[String]): Unit = {
var idate = args(0)
println("date is:" + idate)
val conf = new SparkConf()
.setAppName("AbtestActionMemo")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
val actionLogs: RDD[String] = sc.textFile("abtest_action_logs/dt=" + idate + "/type=t_app_action/*")
//将日志转换成AbtestActionLogsModel类
val actionLogsRdd: RDD[AbtestActionLogsModel] = actionLogs.map(lineToActionClass(_))
//通过caseClassLogRdd获取DAU<1000的projectId和itemId
import sqlContext.implicits._
val actionLogsDataSet = actionLogsRdd.toDS()
actionLogsDataSet.createTempView("actionLogs")
val validProjectFrame: DataFrame = sqlContext.sql("select projectid,planid,count(distinct(uid)) uidCount from actionLogs " +
"where txid in ('1002','2002') " +
"group by projectid,planid " +
"having uidCount>5000 " +
"order by uidCount desc")
//找到有效的projectId
val validProjectsSet: Set[String] = validProjectFrame.rdd.map(row => {
row.getAs[String]("projectid")
}).collect().toSet
validProjectsSet.foreach(println(_))
}
}
3、三者的共性
(1)RDD、DataFrame、Dataset全都是spark平台下的分布式弹性数据集,为处理超大型数据提供便利;
(2)三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算;
(3)三者有许多共同的函数,如filter,排序等;
4、三者的区别
区别:RDD 优点: ①编译时类型安全 ;②面向对象的编程风格 ; ③直接通过类名点的方式来操作数据; 缺点是通信or IO操作都需要序列化和反序列化的性能开销 ,比较耗费性能; GC的性能开销 ,频繁的创建和销毁对象, 势必会增加GC;
DataFrame引入了schema和off-heap堆外内存不会频繁GC,减少了内存的开销; 缺点是类型不安全;
DataSet结合了它俩的优点并且把缺点给屏蔽掉了;
DataFrame也可以叫Dataset[Row],每一行的类型是Row,需要这取每一列的值
val validProjectsSet: Set[String] = validProjectFrame.rdd.map(row => {
row.getAs[String]("projectid")
}).collect().toSet