SparkSQL实战3——DataFrame和Dataset

1、前言

DataFrame并不是Spark最新提出使用的,DataFrame最早是在R、Python语言中使用的。

Dataset是一个分布式的数据集;而DataFrame是一个以列(包括列名、列的类型、列值)的形式构成的分布式数据集,并且按照列赋予不同的名称。在概念层次上,我们可以把DataFrame理解为关系型数据里面的一张表。DataFrame可以通过结构化的数据创建,或者通过Hive中的一张表进行创建,还可以通过已经存在的RDD进行创建等。

RDD vs DataFrame:

2、DataFrame API基本操作

import org.apache.spark.sql.SparkSession

/**
  * @author YuZhansheng
  * @desc DataFrameAPI基本操作
  * @create 2019-03-04 16:45
  */
object DataFrameAPP {

    def main(args: Array[String]): Unit = {

        val spark = SparkSession.builder().appName("DataFrameAPP").master("local[2]").getOrCreate()

        //将json文件加载成一个DataFrame
        val peopleDF = spark.read.format("json").load("file:/soft/spark/examples/src/main/resources/people.json")

        //1、输出DataFrame对应的schema信息
        peopleDF.printSchema()

        //2、输出DataFrame里面的数据,不加参数默认输出前20条
        peopleDF.show(100)

        //3、查询DataFrame里面某一列数据:select name from table;
        peopleDF.select("name").show()

        //4、查询某几列所有数据,并对列进行计算:select name age+10 from table;
        peopleDF.select(peopleDF.col("name"),peopleDF.col("age") + 10).show()

        //5、起个别名:age+10 ==> age2
        peopleDF.select(peopleDF.col("name"),(peopleDF.col("age") + 10).as("age2")).show()

        //6、过滤,输出年龄大于19岁的
        peopleDF.filter(peopleDF.col("age") > 19).show()

        //7、根据某一列进行分组,然后再进行聚合操作:select age,count(1) from table group by age
        peopleDF.groupBy("age").count().show()

        //关闭资源
        spark.stop()
    }
}

3、DataFrame和RDD互操作方式一:反射

import org.apache.spark.sql.SparkSession

/**
  * @author YuZhansheng
  * @desc  DataFrame和RDD互操作方式一
  * @create 2019-03-05 9:57
  */
object DataFrameRDDApp {

    def main(args: Array[String]): Unit = {

        val spark = SparkSession.builder().appName("DataFrameRDDApp").master("local[2]").getOrCreate()

        //使用SparkSession生成RDD
        val rdd = spark.sparkContext.textFile("file:/root/DataSet/infos.txt")

        //将RDD转换为DataFrame
        //注意:需要先导入隐式转换
        import spark.implicits._
        val infoDF = rdd.map(_.split(",")).map(line => Info(line(0).toInt,line(1),line(2).toInt)).toDF()

        //转成DataFrame之后,剩下的操作就和之前的例子一样了!
        infoDF.show()

        //把DataFrame注册为一张表,可以使用SparkSQL语句操作,更简单,参数是要注册成的表名
        infoDF.createOrReplaceTempView("infos")
        spark.sql("select * from infos where age > 30").show()

        spark.stop()
    }

    case class Info(id:Int,name:String,age:Int)
}

4、DataFrame和RDD互操作方式二:通过编程方式实现

比较繁琐。

import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
import org.apache.spark.sql.{Row, SparkSession}

/**
  * @author YuZhansheng
  * @desc   DataFrame和RDD互操作方式二:通过编程的方式实现
  * @create 2019-03-05 10:20
  */
object DataFrameRDD2App {

    def main(args: Array[String]): Unit = {

        val spark = SparkSession.builder().appName("DataFrameRDD2App").master("local[2]").getOrCreate()

        //使用SparkSession生成RDD
        val rdd = spark.sparkContext.textFile("file:/root/DataSet/infos.txt")

        //转换为一个Row
        val infoRDD = rdd.map(_.split(",")).map(line => Row(line(0).toInt,line(1),line(2).toInt))

        //定义一个StructType
        val structType = StructType(Array(StructField("id",IntegerType,true),
            StructField("name",StringType,true),
            StructField("age",IntegerType,true)))

        //获取DataFrame,剩下的就是可以通过DataFrame的API进行操作,也可以使用SQL的方式进行操作
        val infoDF = spark.createDataFrame(infoRDD,structType)

        //打印DataFrame的信息看看是否正确
        infoDF.printSchema()
        infoDF.show()

    }
}

总结:DataFrame和RDD互操作的两种方式,反射方式需要事先知道你的字段和字段类型;优先使用第一种,但是当第一种情况不能满足需求的时候(即事先不知道列信息),再考虑使用第二种编程方式。

5、DataFrame的其他API操作


import org.apache.spark.sql.SparkSession

/**
  * @author YuZhansheng
  * @desc DataFrame的其他操作
  * @create 2019-03-05 10:46
  */
object DataFrameCase {

    def main(args: Array[String]): Unit = {

        val spark = SparkSession.builder().appName("DataFrameCase").master("local[2]").getOrCreate()

        //使用SparkSession生成RDD
        val rdd = spark.sparkContext.textFile("file:/root/DataSet/student.data")

        //将RDD转换为DataFrame
        //注意:需要先导入隐式转换
        import spark.implicits._
        //分隔符“|”前面要加上转义字符,不然会出错
        val studentDF = rdd.map(_.split("\\|")).map(line => Student(line(0).toInt,line(1),line(2),line(3))).toDF()

        //1、不加参数默认显示前20条
        studentDF.show()

        //2、显示30条,不截取
        studentDF.show(30,false)

        //3、获取前十行
        studentDF.take(10)

        //4、取得第一条
        studentDF.first()

        //5、截取指定的列
        studentDF.select("name","email").show(30,false)

        //6、获取name等于空或者等于NULL
        studentDF.filter("name='' OR name='NULL'").show()

        //7、获取名字以m开头的人
        studentDF.filter("SUBSTR(name,0,1)='m'").show()

        //8、按名字排序
        studentDF.sort(studentDF("name")).show()
        //降序排
        studentDF.sort(studentDF("name").desc).show()

        //9、按多个字段排序,默认升序
        studentDF.sort("name","id").show()
        //名字的升序,ID的降序排
        studentDF.sort(studentDF("name").asc,studentDF("id").desc).show()

        //10、对列进行重命名
        studentDF.select(studentDF("name").as("student_name")).show()

        //11、join操作
        val studentDF2 = rdd.map(_.split("\\|")).map(line => Student(line(0).toInt,line(1),line(2),line(3))).toDF()
        studentDF.join(studentDF2,studentDF.col("id") === studentDF2.col("id")).show

        //关闭资源
        spark.stop()
    }

    //使用反射方式将RDD转为DataFrame
    case class Student(id:Int,name:String,phone:String,email:String)
}

6、Dataset概述及使用

虽然DataFrame提供了关系操作和更高的性能,但是他缺乏类型安全性,这会导致运行时错误,因此在Spark1.6中引入DataSetAPI,它结合了RDD和DataFrame这两方面的优势:静态类型、更容易实现RDD的功能特性,以及DataFrame卓越性能特性。在1.6版本中,DataFrame和Dataset还是单独的类,到2.0版本中,Spark将DataFrame和Dataset API统一起来,为开发人员提供了单一的API,DataFrame是一个特定的Dataset[T],其中T=行的类型,因此DataFrame和Dataset享有相同的方法。


import org.apache.spark.sql.SparkSession

/**
  * @author YuZhansheng
  * @desc  Dataset操作
  * @create 2019-03-06 15:45
  */
object DatasetApp {
    def main(args: Array[String]): Unit = {

        val spark = SparkSession.builder().appName("DatasetApp").master("local[2]").getOrCreate()

        val path = "file:/root/DataSet/sales.csv"

        //spark解析CSV文件
        val df = spark.read.option("header","true").option("inferSchema","true").csv(path)

        df.show

        //注意:需要导入隐式转换
        import spark.implicits._

        //获取Dataset
        val ds = df.as[Sales]

        //只取出一行的itemId
        ds.map(line => line.itemId).show()

        spark.stop()
    }

    case class Sales(transactionId:Int,customerId:Int,itemId:Int,amountPaid:Double)
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值