【时间】2021.12.01
【题目】【Spark入门(3)】SparkSQL基础
目录
一、引言
本文是课程尚硅谷大数据Spark教程的SparkSQL基础部分的思维导图。SparkSQL主要是通过sql语句来简化RDD的开发流程,主要内容包括:
- SparkSQL历史(从Hive到Shark,再到剥离Hive依赖的SparkSQL)
- 两个数据抽象:DataFrame和DataSet,其中DF是一种以RDD为基础的包含schema 元信息的二维表格数据,属于弱类型;DS是DF的强类型扩展,type DataFrame = Dataset[Row]
- SparkSQL 核心编程,包括加载与保存数据,RDD、DF、DS之间的转换等
- UDF用户定义函数和UDAF用户定义聚合函数的实现,新版本的Spark统一继承Agreegator即可。
视频链接:SparkSQL基础
二、一些重点图
1、RDD与DataFrame
2、RDD、DF、DS三者的相互转换
3、SparkSQL核心编程例子
1)spark-shell例子:
- SQL语法
- DSL语法:
2)IDEA例子:
package com.atguigu.bigdata.spark.sql
import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}
object Spark01_SparkSQL_Basic {
def main(args: Array[String]): Unit = {
// TODO 创建SparkSQL的运行环境
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("sparkSQL")
val spark = SparkSession.builder().config(sparkConf).getOrCreate()
import spark.implicits._
// TODO 执行逻辑操作
// TODO DataFrame
//val df: DataFrame = spark.read.json("datas/user.json")
//df.show()
// DataFrame => SQL
// df.createOrReplaceTempView("user")
//
// spark.sql("select * from user").show
// spark.sql("select age, username from user").show
// spark.sql("select avg(age) from user").show
// DataFrame => DSL
// 在使用DataFrame时,如果涉及到转换操作,需要引入转换规则
//df.select("age", "username").show
//df.select($"age" + 1).show
//df.select('age + 1).show
// TODO DataSet
// DataFrame其实是特定泛型的DataSet
//val seq = Seq(1,2,3,4)
//val ds: Dataset[Int] = seq.toDS()
//ds.show()
// RDD <=> DataFrame
val rdd = spark.sparkContext.makeRDD(List((1, "zhangsan", 30), (2, "lisi", 40)))
val df: DataFrame = rdd.toDF("id", "name", "age")
val rowRDD: RDD[Row] = df.rdd
// DataFrame <=> DataSet
val ds: Dataset[User] = df.as[User]
val df1: DataFrame = ds.toDF()
// RDD <=> DataSet
val ds1: Dataset[User] = rdd.map {
case (id, name, age) => {
User(id, name, age)
}
}.toDS()
val userRDD: RDD[User] = ds1.rdd
// TODO 关闭环境
spark.close()
}
case class User( id:Int, name:String, age:Int )
}
4、一个UDAF的例子(实现计算平均年龄)
package com.atguigu.bigdata.spark.sql
import org.apache.spark.SparkConf
import org.apache.spark.sql.expressions.Aggregator
import org.apache.spark.sql.{Dataset, Encoder, Encoders, SparkSession, TypedColumn, functions}
object Spark03_SparkSQL_UDAF2 {
def main(args: Array[String]): Unit = {
// TODO 创建SparkSQL的运行环境
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("sparkSQL")
val spark = SparkSession.builder().config(sparkConf).getOrCreate()
import spark.implicits._
val df = spark.read.json("datas/user.json")
// 早期版本中,spark不能在sql中使用强类型UDAF操作
// SQL & DSL
// 早期的UDAF强类型聚合函数使用DSL语法操作
val ds: Dataset[User] = df.as[User]
// 将UDAF函数转换为查询的列对象
val udafCol: TypedColumn[User, Long] = new MyAvgUDAF().toColumn
ds.select(udafCol).show
// TODO 关闭环境
spark.close()
}
/*
自定义聚合函数类:计算年龄的平均值
1. 继承org.apache.spark.sql.expressions.Aggregator, 定义泛型
IN : 输入的数据类型 User
BUF : 缓冲区的数据类型 Buff
OUT : 输出的数据类型 Long
2. 重写方法(6)
*/
case class User(username:String, age:Long)
case class Buff( var total:Long, var count:Long )
class MyAvgUDAF extends Aggregator[User, Buff, Long]{
// z & zero : 初始值或零值
// 缓冲区的初始化
override def zero: Buff = {
Buff(0L,0L)
}
// 根据输入的数据更新缓冲区的数据
override def reduce(buff: Buff, in: User): Buff = {
buff.total = buff.total + in.age
buff.count = buff.count + 1
buff
}
// 合并缓冲区
override def merge(buff1: Buff, buff2: Buff): Buff = {
buff1.total = buff1.total + buff2.total
buff1.count = buff1.count + buff2.count
buff1
}
//计算结果
override def finish(buff: Buff): Long = {
buff.total / buff.count
}
// 缓冲区的编码操作
override def bufferEncoder: Encoder[Buff] = Encoders.product
// 输出的编码操作
override def outputEncoder: Encoder[Long] = Encoders.scalaLong
}
}