在spark中有重要的组件SparkContext和SQLContext,在读取数据文件时我们可以通过这两个组件进行不同形式的读取,比如:
val conf = new SparkConf().setMaster("local").setAppName("testRead")
val sc = new SparkContext(conf)
val readFile = sc.textFile("C:\\Users\\Desktop\\part-00006")
这种方式就是使用SparkContext进行文件读取,通过该种方式,我们可以读取普通的文本文件(无后缀名),.txt文件。而使用SQLContext读取的文件格式较多,分别如下:
val conf = new SparkConf().setMaster("local").setAppName("testRead")
val sc = new SparkContext(conf)
val ssc = new SQLContext(sc)
ssc.read.text() //文本文件(包括txt文件和无扩展名的文本文件)
ssc.read.parquet() //一种大数据文件,存储内容和格式都与文本文件一致;
ssc.read.json() //读取json文件或者json字符串
无论使用上述哪种方式去读取文件,我们都可以得到期望的数据集,但是两种读取方式的结果集类型却是不同,因此结果集的具体操作也就不同,如下图:
通过上面图我们可以清楚的看到两种方式的结果集分别是RDD[T]和DataFrame,接下来就跟随小编一起来看它们之间的区别;
No1.以Person实体为例探究RDD和DataFrame
当我们以两种不同的方式读取到Person数据,Person会作为RDD的类型参数,但是Spark无法知晓内部结构,而dataFrame可以清楚加载到Person实体的内部结果和具体的数据:
RDD虽然以Person为类型参数,但是Spark框架并不了解Person类的内部结构;右侧的DataFrame却提供了详细的结构信息,使得Spark Sql可以清楚地知道数据集中有哪些列,每列的名称和类型分别是什么。
DataFrame中多了数据集的结构信息即Schema,所以我们在获取到DataFrame结果集之后可以通过printSchema方法来查看当前数据文件的结构信息。所以我们可以这样理解,RDD是分布式的Java对象集合(这也就是为什么RDD会有Broadcast广播变量的方法),DataFrame是分布式的Row对象的集合。
DataFrame除了提供比RDD更丰富的算子之外,更重要的特点是提升执行效率、减少数据读取以及执行计划的优化。
No2.DataSet和DataFrame的对比
DataSet可以理解成DataFrame的一种特例,主要区别是DataSet每一个record存储的是一个强类型值而不是一个Row。
DataFrame和DataSet可以相互转化,df.as[ElementType]这样可以把DataFrame转化为DataSet,ds.toDF()这样可以把DataSet转化为DataFrame。
No3.区别
✎.RDD:
不支持SparkSql操作
RDD一般和spark mlib同时使用
✎.DataFrame:
1. 与RDD和Dataset不同,DataFrame每一行的类型固定为Row,只有通过解析才能获取各个字段的值,无法直接获取每一列的值:
testDF.foreach{
line =>
val col1=line.getAs[String]("col1")
val col2=line.getAs[String]("col2")
}
2. 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)
3. 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()
✎.DataSet与DataFrame
1. DataFrame也可以叫做DataSet[Row],每一行的类型都是Row,不解析我们就无法知晓其中有哪些字段,每个字段又是什么类型。我们只能通过getAs[类型]或者row(i)的方式来获取特定的字段内容
2. 而在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,处理文本文件使用第一种读取方式比较多,第二种读取方式一般用来读取parquet。