Spark编程之深入理解DataSet

1.前言

DataSet是Spark重要的数据结构之一拥有比RDD更高的性能,比DataFrame更灵活的操作方式,是Spark SQL的扩展,提供了额外的编译时类型检查。本文将深入介绍DataSet的使用。

从Spark2.0开始,DataFrame成为了DataSet的特例,即DataFrame是DataSet的特殊情况。DataFrame是操作Row对象的DataSet。当数据集可以被编码成SparkSQL并且在编译时知道类型信息的时候可以使用DataSet。DataSet是混合了DataFrame和RDD的强类型分布式集合。

2.DataSet与DataFrame、RDD之间的相互转换

//DataFrame转DataSet
def fromDF(df: DataFrame): Dataset[Student] = {
    df.as[Student]
}
//DataSet转RDD
def toRDD(ds: Dataset[RawPanda]): RDD[RawPanda] = {
    ds.rdd
}
//DataFrame转DataSet
def toDF(ds: Dataset[RawPanda]): DataFrame = {
    ds.toDF()
}

在传统DataFrame上使用Dataset的原因之一是编译时强类型的。DataFrame具有运行时模式信息,但缺少有关模式的编译时信息。这种强类型在创建库时特别有用,因为您可以更清楚地指定输入的要求和返回类型。

3.深入理解Dataset API

Dataset API的主要优势之一是可以更轻松地与Scala和Java代码集成。这样既保留了DataFrame拥有更多信息的schema的优势,同时又可以像操作RDD一样灵活

3.1需求

下面通过一个简单的需求详细介绍如果灵活使用DataSet API。

需求:有一张学生表(id,name,age,score),求成绩大于80的学生的姓名及成绩

3.2类RDD编程

DataSet使用与RDD函数类似的函数签名如:filter,map,mapPartitions和flatMap等。

//DataSet的类RDD操作:
case class Stu2(name:String, id:Int, age:Int, score:Int)
def testDataSet(session: SparkSession): Unit = {
    //用于隐式转换
    import session.implicits._
    //加载mysql数据库中的数据进行测试
    val kTopic = session.read.format("jdbc")
    .option("url", MY_URL)
    .option("dbtable", MY_DBTABLE)
    .option("driver", MYSQL_DRIVER)
    .option("user", MY_USER)
    .option("password", MY_PASSWD)
    val wlTable = kTopic.load() 
    val dsStu2 = wlTable.as[Stu2] //将DataFrame转为Student类型的DataSet
    //使用类RDD操作方式将成绩大于80的学生的姓名和成绩筛选出来
    val likeRDD = dsStu2.filter(row => row.score > 80).map(row => (row.name, row.score))
    likeRDD.show(false) //likeRDD类型是DataSet[(String,Int)]
}

3.3类DataFrame操作

上面是类RDD的操作,DataSet还有类DataFrame的关系型操作:

//DataSet的类DataFrame操作
case class Stu2(name:String, id:Int, age:Int, score:Int)
def testDataSet(session: SparkSession): Unit = {
    import session.implicits._
    val kTopic = session.read.format("jdbc")
    .option("url", MY_URL)
    .option("dbtable", MY_DBTABLE)
    .option("driver", MYSQL_DRIVER)
    .option("user", MY_USER)
    .option("password", MY_PASSWD)
    val wlTable = kTopic.load() 
    val dsStu2 = wlTable.as[Stu2] 
  
    //使用类RDD操作方式将成绩大于80的学生的姓名和成绩筛选出来,下面两行完全一样
    val likeDF1 = dsStu2.select(col("name"),col("score")).where(col("score")>80)
    val likeDF2 = dsStu2.select($"name",$"score" ).where($"score" > 80)
    likeDF1.show() //likeDF1 ==>DataSet[Row]
    likeDF2.show() //likeDF2 ==>DataSet[Row]
}
//类RDD和类DataFrame混编,likeRDD是上面类RDD编程中最后得到的变量,为了方便直接用了
likeRDD.orderBy(col("_2") )//likeRDD是用的类RDD编程。但是orderBy很显然是类DataFrame编程,这种情况可以

其实已经注意到了,上面两种方式可以得到相同的效果,但是变量的类型韩式不尽相同的。比如dsStu2.select(col("name"),col("score"))虽然dsStu2是DataSet类型但是通过select函数以后变成了DataFrame。

即某些操作(例如select)同时具有类型化和未类型化的实现。如果您提供的是列而不是通过TypedColumn,将获得一个DataFrame而不是一个Dataset。

4.总结

DataSet是Spark编程模型中的核心概念之一,拥有极高的性能。同时DataSet用于比RDD更多的schema信息,比DataFrame更灵活的操作数据集方式,是开发Spark程序的首选。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值