spark rdd dataframe dataset

RDD

RDD(Resilient Distribute Datasets)弹性分布式数据集,是spark的核心概念,表示分布式存储的只读集合,可以基于RDD进行数据的转换操作(map,filter等)

Spark通过RDD的抽象概念,实现了分区计算存储、DAG、依赖等编程接口

rdd介绍:https://www.infoq.cn/article/spark-core-rdd

RDD vs DataFrame

以People为例,有id和name两个字段

case class People(id: Int, name: String)

val ps = Seq(People(1, "mwf"), People(2, "zqr"))
//peopleRDD的类型为RDD[Person]
val peopleRdd = spark.sparkContext.parallelize(ps)
peopleRdd.foreach( f => {
    //f类型为People
    println(s"${f.id} -- ${f.name}")
})

import spark.implicits._
//peopleDF的类型为DataFrame
val peopleDF = peopleRdd.toDF()
peopleDF.foreach( f => {
    //f类型为Row
    println(s"${f.getAs("id")} -- ${f.getAs("name")}")
})

可以看到RDD相当于是People类的集合,而DataFrame相当于是Row类型的集合

作为使用者,在操作RDD时候,我们可以在编译时明了的了解到People的字段,进行操作;而操作DataFrame时,其封装了row类型,我们要通过row.get()来获得字段,进行操作。

最明显的区别就是,使用RDD可以直接通过点字段的方式来操作(f.id),而DataFrame则不行。

但是DataFrame比RDD多了数据的结构类型,通过Row对象可以获得schema(row.schema),DataFrame基于SparkSQL引擎,可以进行优化,提高执行效率,减少数据读取

RDD优点:
  • 编译时类型安全

  • 编译时就能检查出类型错误

  • 面向对象的编程风格

  • 直接通过类名点的方式来操作数据

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

DataFrame引入了schema和off-heap

schema : RDD每一行的数据, 结构都是一样的,这个结构就存储在schema中。 Spark通过schema就能够读懂数据, 因此在通信和IO时就只需要序列化和反序列化数据, 而结构的部分就可以省略了。

off-heap : 意味着JVM堆以外的内存, 这些内存直接受操作系统管理(而不是JVM)。Spark能够以二进制的形式序列化数据(不包括结构)到off-heap中, 当要操作数据时,就直接操作off-heap内存。由于Spark理解schema,所以知道该如何操作。

DataSet

DataSet结合了RDD和DataFrame的优点,并带来的一个新的概念Encoder。

当序列化数据时,Encoder产生字节码与off-heap进行交互,能够达到按需访问数据的效果,而不用反序列化整个对象

RDD和DataSet

DataSet以Catalyst逻辑执行计划表示,并且数据以编码的二进制形式被存储,不需要反序列化就可以执行sorting、shuffle等操作

DataSet创立需要一个显式的Encoder,把对象序列化为二进制,可以把对象的scheme映射为Spark SQL类型,然而RDD依赖于运行时反射机制

DataSet比RDD性能要好很多

DataFrame和DataSet

DataFrame看做是DataSet的一个特例

Dataset每一个record存储的是一个强类型值而不是一个Row

DataSet可以在编译时检查类型

DataSet是面向对象的编程接口。

后面版本DataFrame会继承DataSet,DataFrame是面向Spark SQL的接口。

DataFrame和DataSet可以相互转化,df.as[ElementType]这样可以把DataFrame转化为DataSet,ds.toDF()这样可以把DataSet转化为DataFrame。

三者的相互转换

    // 通过集合创建rdd
    // 调用parallelize会把集合中的数据拷贝到集群中,形成分布式的数据集合(RDD)
    val arr = Array("1,mwf","2,zqr")
    val rdd = spark.sparkContext.parallelize(arr)
    // 可以指定将集合切为几个分区
    val rdd1 = spark.sparkContext.parallelize(arr, 2)
    rdd.foreach(println(_))
    rdd1.foreach(println(_))

    //通过文本创建RDD
    val textRdd = spark.sparkContext.textFile("hdfs://hadoop01:9000/demo/words.txt")
    textRdd.flatMap(_.split(","))
      .map((_, 1))
      .reduceByKey(_+_)


    // 通过RDD[Row]和schema(StructType)创建dataframe
    // 创建schema(StructType)
    val schema = new StructType()
      .add("id", IntegerType)
      .add("name", StringType)
    val schema1 = StructType(
      Array(
        StructField("id", IntegerType, true),
        StructField("name", StringType, false)
      ))
    val rowRdd = rdd.map(_.split(","))
        .map( x => Row(x(0).toInt, x(1)))
    spark.createDataFrame(rowRdd, schema)

    //通过隐式转换的方式创建dataframe
    //会隐式转换为Row类型
    import spark.implicits._
    val df = rdd.map(_.split(","))
      .map( x => People(x(0).toInt, x(1)))
      .toDF()
    df.show

    //从DF中取值
    df.map( row => {
      //通过下标取
      row.get(0)
      //通过字段名取
      row.getAs("id")
    })

    //DataFrame转为DataSet
    val ds = df.as[People]


    val seq = Seq(People(1, "mwf"))

    val peopleDF = seq.toDF()
    peopleDF.show()
    peopleDF.map( x => {
      x.getAs("id")
    })
    val peopleDs = seq.toDS()
    peopleDs.show()
    peopleDs.map( x => {
      x.id
    })

    val peoDs = spark.createDataset(seq)

    peoDs.rdd
    peopleDF.rdd
参考地址

https://blog.csdn.net/u013063153/article/details/53317627


慢慢积累,总是好的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值