RDD,DataFrame,DataSet区别

RDD

优点:

  • 1.编译时类型安全
    编译时就能检查出类型错误 (_.age > “”) 能检测”” 空字符串
  • 2.面向对象的编程风格 ( _.age )
    直接通过类名点的方式来操作数据

缺点:

  • 1.序列化和反序列化的性能开销
    无论是集群间的通讯,还是IO操作都需要对对象的结构和数据进行序列化和反序列化
  • 2.GC的性能开销
    频繁的创建和销毁对象,势必会增加GC
package rdddataframadataset

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext

/**
  * Created by Administrator on 2017/3/15.
  */
object RddTest {
  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName("test").setMaster("local")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    val sqlContext = new SQLContext(sc)

    /**
      * id      age
      * 1       30
      * 2       29
      * 3       21
      */
    case class Person(id: Int, age: Int)
    val idAgeRDDPerson = sc.parallelize(Array(Person(1, 30), Person(2, 29), Person(3, 21)))

    // 优点1
    // idAge.filter(_.age > "") // 编译时报错, int不能跟String比

    // 优点2
    idAgeRDDPerson.filter(_.age > 25) // 直接操作一个个的person对象
  }

}

DataFrame

优点:

  • 1.只需要序列化数据,不需要序列化结构
  • 2.不受GC影响

缺点:

  • 1.不是面对对象风格 ( _.age )
  • 2.运行时检查错误 ( idAgeDF.col(“aage”) ) 没有aage这个列

DataFrame引入了schema和off-heap

  • schema : RDD每一行的数据,结构都是一样的,这个结构就存储在schema中.Spark通过schema就能够读懂 数据,因此在通讯和IO时就只需要序列化和反序列化数据, 而 结构部分 就可以 省略
  • off-heap : 意味着JVM对以外的内存,这些内存直接受操作系统管理(而不是Jvm),Spark能够以二进制的形式序列化数据(不包括结构)到off-heap中,当要操作系统时,就直接操作off-heap内存,由于spark 理解schema,所以知道怎么做
  • off-heap就像地盘, schema就像地图, Spark有地图又有自己地盘了, 就可以自己说了算了, 不再受JVM的限制, 也就不再收GC的困扰了.
  • 通过schema和off-heap, DataFrame解决了RDD的缺点, 但是却丢了RDD的优点. DataFrame不是类型安全的, API也不是面向对象风格的.
package rdddataframadataset

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{Row, SQLContext}
import org.apache.spark.sql.types.{DataTypes, StructField, StructType}

/**
  * Created by Administrator on 2017/3/15.
  */

object DataFrameTest {
  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName("test").setMaster("local")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    val sqlContext = new SQLContext(sc)
    /**
      * id      age
      * 1       30
      * 2       29
      * 3       21
      */
    val idAgeRDDRow = sc.parallelize(Array(Row(1, 30), Row(2, 29), Row(4, 21)))

    val schema = StructType(Array(StructField("id", DataTypes.IntegerType), StructField("age", DataTypes.IntegerType)))

    val idAgeDF = sqlContext.createDataFrame(idAgeRDDRow, schema)
    // API不是面向对象的
    idAgeDF.filter(idAgeDF.col("age") > 25).show()
    // 不会报错, DataFrame不是编译时类型安全的
    idAgeDF.filter(idAgeDF.col("age") > "").show()
  }

}

DataSet

ps:DataSet 1.6.0 版本才有

优点:

  • 1.DataSet可以在编译时检查类型
  • 2.并且是面向对象的编程接口
  • 3.只需要序列化数据,不需要序列化结构
  • 4.不受GC影响

DataSet结合了RDD和DataFrame的优点, 并带来的一个新的概念Encoder当序列化数据时, Encoder产生字节码与off-heap进行交互, 能够达到按需访问数据的效果,而不用反序列化整个对象. Spark还没有提供自定义Encoder的API, 但是未来会加入.

package rdddataframadataset

import org.apache.spark.sql.types.{DataTypes, StructField, StructType}
import org.apache.spark.sql.{Row, SQLContext}
import org.apache.spark.{SparkConf, SparkContext}

/**
  * Created by Administrator on 2017/3/15.
  */
//定义的class 必须放在类的外面,填坑,不知道为什么
case class Persons(name: String, age: Long)

object DataSetTest {


  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName("test").setMaster("local") 
    val sc = new SparkContext(conf)
    val sqlContext = new SQLContext(sc)

    import sqlContext.implicits._

    // 目前支持String, Integer, Long等类型直接创建Dataset
    //Creating Datasets

    //第一种
    Seq(1, 2, 3).toDS().show()

    //第二种
    val ds = Seq(Persons("Andy", 32)).toDS()
    ds.show()

    //第三种
    val idAgeRDDRow = sc.parallelize(Array(Row(1, 30), Row(2, 29), Row(4, 21)))
    val schema = StructType(Array(StructField("id", DataTypes.IntegerType), StructField("age", DataTypes.IntegerType)))
    // 在2.0.0-preview中这行代码创建出的DataFrame, 其实是DataSet[Row]

    val idAgeDS = sqlContext.createDataFrame(idAgeRDDRow, schema)
    idAgeDS.show()

    //第四种
    import sqlContext.implicits._    //隐式函数
  /*  1.序列化
      2. 序列化成对象,调用对象属性*/
    val PersionDF = sqlContext.read.json("d://SparkProject//demo1//testdata//person.json").as[Persons]
    PersionDF.show()
    //第五种
    sqlContext.createDataset(sc.parallelize(Array(1, 2, 3))).show()
  }


}

总结:
1、RDD支持面向java、scala对象,编译时强类型检查。缺点,序列化非常消耗时间(集群分发和磁盘存储),不能充分利用系统的高级优化能力(如off-heap),垃圾回收对象开销大。

2、DataFrame支持数据集的模式表示(即数据列的概念),所以集群分发数据时并不需要序列化,能充分利用系统高级优化能力(off-heap),引入查询计划提高性能。缺点,DataFrame的列类型,在编译时无法判断类型,会产生运行时错误。

3、Dataset即支持数据集的模式表示,又支持java、scala对象的类型检查能力。两者通过引入一种编码、解码机制来实现。

你可能感兴趣的:(Spark)