DataFrame / DataSet / RDD的关系:
RDD是Spark的基石,因为其他的spark框架都是运行在Spark core上的.但是在我们Spark sql里面,就有点区别了.
在Spark sql中,DataSet是核心,没有之一.但是DataSet仅限于Spark sql中,不能在其他框架中使用,所以RDD依旧还是spark的基石,依旧是核心.而DataFrame已经被DataSet替换了,DataFrame能实现的功能,DataSet都能实现,相反,DataFrame却不能.
三者的关系如下:
RDD + schema(数据的结构信息) = DataFrame = DataSet[Row]
RDD 0.x版本发布, DataFrame1.3版本发布, DataSet1.6版本发布.
RDD: 提供了很多实用简单的API
DataFrame: DataFrame可以理解为一个传统数据库的二维表格,除了数据以外,还记录着数据的结构信息,即schema.DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好
DataSet: DataSet[Row] = Dataframe ; 它是Dataframe API的一个扩展,是spark最新的数据抽象,也是Spark SQL中最核心的组件,它基本代替了Dataframe,也有完全代替Dataframe的趋势.
注: RDD不支持spark sql的操作
RDD / DataSet / Dataframe之间的转换
上面说到RDD不支持Spark sql的操作,但是Spark生态圈只提供了Spark core一个计算框架,且Spark生态圈都是基于Spark core进行计算的,所以Spark core对接Spark sql的方式就是:将RDD转换为DataSet / Dataframe,且三者之间支持互相转换!
转换之前先聊一下DataFrame支持两种查询方式:一种是DSL风格,另外一种是SQL风格,dataFrame支持两者查询风格
DSL: 你需要引入 import spark.implicit._ 这个隐式转换,可以将DataFrame隐式转换成RDD。
SQL: 你需要将DataFrame注册成一张表格,且需要通过sparkSession.sql 方法来运行你的SQL语句
用Spark-shell来操作Spark SQL,spark作为SparkSession的变量名,sc作为SparkContext的变量名.
将文件中的数据转换成DataSet //先case一个类
case class person(name:String,age:Int)
//将文件里面的数据转换成DataSet
val peopleDF2 =spark.sparkContext.textFile("../examples/src/main/resources/people.txt").map(_.split(",")).map(para=> Person(para(0).trim,para(1).trim.toInt)).toDS
//制成一张person的表
//制作一个临时表,之后就可以使用spark.sql("这里面是sql语句")
peopleDF2.createOrReplaceTempView("persons")
//查询
val teen =spark.sql("select * from persons where age between 13 and 30")
//因为DataFrame=DataSet[row],所以要访问row对象中的每一个元素,
//可以通过这种row[0]角标的方式来访问,上面是通过反射获取schema
teen.map(row => "name:" + row(0)).show
//将RDD转换成DataFrame
var peopleRDD = sc.textFile("../examples/src/main/resources/people.txt")
peopleRDD.collect
//以”,”切割,得到一个Array,然后再用map对里面的每一个元素都进行转换,最后用toDF方法给这两个起名字,这里的para也可以是一个样例类,与下面变成DataSet一样,唯一的区别在于最后为toDF,这样的话toDF里面就不需要给定名称了
val peopleDF =peopleRDD.map(_.split(",")).map(para=>(para(0).trim(),para(1).trim().toInt)).toDF("name","age")
//将 DataFrame转换成RDD
val aa = peopleDF.rdd
//将RDD转换成DataSet
//先定义一个case实例,最后是直接toDS就ok了
case class person(name:String,age:Int)
val peopleDF= peopleRDD.map(_.split(",")).map(para=>person(para(0).trim(),para(1).trim().toInt)).toDS
//将DataSet转换成RDD
val bb = peopleDF.rdd //和上面一样,一个方法搞定
//将DataFrame转换成DataSet
val peopleDS = peopleDF.as[person] //as那个case的类,意思就是告诉每一列的类型是什么
//将DataSet转换成DataFrame
PeopleDS.toDF //用的toDF方法,相当于直接把类型信息去掉