一、UDF
用户可以通过 spark.udf 功能添加自定义函数,实现自定义功能
快速入门
案例说明:再查询的字段数据前加上字符串
user.json文件
package com.bigdata.SparkSQL
import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame,SparkSession}
/**
* @author wangbo
* @version 1.0
*/
object Spark01_SparkSQL_UDF {
def main(args: Array[String]): Unit = {
// TODO 创建SparkSQL的运行环境
val sparkConf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("sparkSQL")
val sparkSession: SparkSession = SparkSession.builder().config(sparkConf).getOrCreate()
import sparkSession.implicits._
val df: DataFrame = sparkSession.read.json("datas/user.json")
df.createOrReplaceTempView("user")
//用户自定义一个函数,在字符串的前面加 "Name"
sparkSession.udf.register("prefixName",(name:String) => {
"Name" + name
})
//实现功能:在查询语句中前加字符串
sparkSession.sql("select age,prefixName(username) from user").show()
// TODO 关闭环境
sparkSession.close()
}
}
二、UDAF
UDAF:即用户定义的聚合函数
强类型的 Dataset 和弱类型的 DataFrame 都提供了相关的聚合函数, 如 count(),countDistinct(),avg(),max(),min()。除此之外,用户可以设定自己的自定义聚合函数。通过继承 UserDefinedAggregateFunction 来实现用户自定义弱类型聚合函数。从 Spark3.0 版本后,UserDefinedAggregateFunction 已经不推荐使用了。可以统一采用强类型聚合函数Aggregator
快速入门
案例说明:自定义聚合函数求计算年龄的平均值
user.json文件
package com.bigdata.SparkSQL
import org.apache.spark.sql.expressions.Aggregator
import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, Encoder, Encoders, SparkSession, functions}
/**
* @author wangbo
* @version 1.0
*/
object Spark01_SparkSQL_UDAF {
def main(args: Array[String]): Unit = {
// TODO 创建SparkSQL的运行环境
val sparkConf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("sparkSQL")
val sparkSession: SparkSession = SparkSession.builder().config(sparkConf).getOrCreate()
val df: DataFrame = sparkSession.read.json("datas/user.json")
df.createOrReplaceTempView("user")
//将强类型的函数转换成弱类型的操作
sparkSession.udf.register("ageAvg",functions.udaf(new MyAvgUDAF()))
sparkSession.sql("select ageAvg(age) from user").show()
// TODO 关闭环境
sparkSession.close()
}
/*
自定义聚合函数:计算年龄的平均值
1.定义自定义类继承org.apache.spark.sql.expressions.Aggregator
定义泛型
IN:输入的数据类型
BUF:缓冲区的数据类型(使用了样例类)
OUT:输出的数据类型
2.重写方法
*/
//样例类 total保存年龄的和,count保存用户数量
case class Buff(var total:Long, var count:Long)
class MyAvgUDAF extends Aggregator[Long,Buff,Long]{
//初始值,缓冲区初始化
override def zero: Buff = {
Buff(0L,0L)
}
//根据输入的数据更新缓冲区的数据
override def reduce(buff: Buff, in: Long): Buff = {
buff.total = buff.total + in
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
}
//缓冲区的编码操作,自定义的类就写Encoders.product,如果是scala存在的类,如Long 就写Encoders.scalaLong
override def bufferEncoder: Encoder[Buff] = Encoders.product
//输出的编码操作,自定义的类就写Encoders.product,如果是scala存在的类,如Long 就写Encoders.scalaLong
override def outputEncoder: Encoder[Long] = Encoders.scalaLong
}
}