在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字符串

 

      无论使用上述哪种方式去读取文件,我们都可以得到期望的数据集,但是两种读取方式的结果集类型却是不同,因此结果集的具体操作也就不同,如下图:

spark 处理单个大文件 spark读取dat文件_spark 处理单个大文件

通过上面图我们可以清楚的看到两种方式的结果集分别是RDD[T]和DataFrame,接下来就跟随小编一起来看它们之间的区别;

 No1.以Person实体为例探究RDD和DataFrame

          

当我们以两种不同的方式读取到Person数据,Person会作为RDD的类型参数,但是Spark无法知晓内部结构,而dataFrame可以清楚加载到Person实体的内部结果和具体的数据:

spark 处理单个大文件 spark读取dat文件_字段_02

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。