【Spark征服之路-3.6-Spark-SQL核心编程(五)】

自定义函数:

UDF:

val sparkConf = new SparkConf().setMaster("local[*]" ).setAppName("SQLDemo" )
// 创建 SparkSession 对象
val spark :SparkSession = SparkSession.builder ().config(sparkConf).getOrCreate()

import spark.implicits._
// 读取 json 文件
val df : DataFrame = spark.read.json("Spark-SQL/input/user.json" )

spark.udf.register("addName" ,(x:String)=>"Name:" +x)

df.createOrReplaceTempView("people" )
spark.sql("select addName(username),age from people" ).show()

spark.stop()

UDAF(自定义聚合函数)

强类型的 Dataset 和弱类型的 DataFrame 都提供了相关的聚合函数, 如 count(),

countDistinct(),avg(),max(),min()。除此之外,用户可以设定自己的自定义聚合函数。Spark3.0之前我们使用的是UserDefinedAggregateFunction作为自定义聚合函数,从 Spark3.0 版本后可以统一采用强类型聚合函数 Aggregator

实验需求:计算平均工资

实现方式一:RDD

val sparkconf: SparkConf = new SparkConf().setAppName("app" ).setMaster("local[*]" )
val sc: SparkContext = new SparkContext(conf)
val resRDD: (Int, Int) = sc.makeRDD(List (("zhangsan" , 20), ("lisi" , 30), ("wangw u " ,40))).map {
case (name, salary) => {
(salary, 1)
}
}.reduce {
(t1, t2) => {
(t1._1 + t2._1, t1._2 + t2._2)
}
}
println (resRDD._1/resRDD._2)
// 关闭连接
sc.stop()

实现方式二:弱类型UDAF

class MyAverageUDAF extends UserDefinedAggregateFunction{
def inputSchema: StructType =
StructType (Array (StructField ("salary" ,IntegerType)))
// 聚合函数缓冲区中值的数据类型 (salary,count)
def bufferSchema: StructType = {

StructType (Array (StructField ("sum" ,LongType),StructField ("count" ,LongType)))
}
// 函数返回值的数据类型
def dataType: DataType = DoubleType
// 稳定性:对于相同的输入是否一直返回相同的输出。
def deterministic: Boolean = true
// 函数缓冲区初始化
def initialize(buffer: MutableAggregationBuffer): Unit = {
// 存薪资的总和
buffer(0) = 0L
// 存薪资的个数
buffer(1) = 0L
}
// 更新缓冲区中的数据
def update(buffer: MutableAggregationBuffer,input: Row): Unit = {
if (!input.isNullAt(0)) {
buffer(0) = buffer.getLong(0) + input.getInt(0)
buffer(1) = buffer.getLong(1) + 1
}
}
// 合并缓冲区
def merge(buffer1: MutableAggregationBuffer,buffer2: Row): Unit = {
buffer1(0) = buffer1.getLong(0) + buffer2.getLong(0)
buffer1(1) = buffer1.getLong(1) + buffer2.getLong(1)
}
// 计算最终结果
def evaluate(buffer: Row): Double = buffer.getLong(0).toDouble /
buffer.getLong(1)
}

val sparkconf: SparkConf = new SparkConf().setAppName("app" ).setMaster("local[*]" )
val spark:SparkSession = SparkSession.builder ().config(conf).getOrCreate()

import spark.implicits._
val res :RDD[(String,Int)]= spark.sparkContext.makeRDD(List (("zhangsan" , 20), ("lisi" , 30), ("wangwu" ,40)))

val df :DataFrame = res.toDF("name" ,"salary" )
df.createOrReplaceTempView("user" )
var myAverage = new MyAverageUDAF
// spark 中注册聚合函数
spark.udf.register("avgSalary" ,myAverage)
spark.sql("select avgSalary(salary) from user" ).show()

// 关闭连接
spark.stop()

实现方式三:强类型UDAF

case class Buff(var sum:Long,var cnt:Long)
class MyAverageUDAF extends Aggregator[Long,Buff,Double]{
override def zero: Buff = Buff (0,0)
override def reduce(b: Buff, a: Long): Buff = {
b.sum += a
b.cnt += 1
b
}
override def merge(b1: Buff, b2: Buff): Buff = {
b1.sum += b2.sum
b1.cnt += b2.cnt
b1
}
override def finish(reduction: Buff): Double = {
reduction.sum.toDouble/reduction.cnt
}
override def bufferEncoder: Encoder[Buff] = Encoders.product
override def outputEncoder: Encoder[Double] = Encoders.scalaDouble

}

val sparkconf: SparkConf = new SparkConf().setAppName("app" ).setMaster("local[*]" )
val spark:SparkSession = SparkSession.builder ().config(conf).getOrCreate()

import spark.implicits._
val res :RDD[(String,Int)]= spark.sparkContext.makeRDD(List (("zhangsan" , 20), ("lisi" , 30), ("wangwu" ,40)))

val df :DataFrame = res.toDF("name" ,"salary" )
df.createOrReplaceTempView("user" )
var myAverage = new MyAverageUDAF
// spark 中注册聚合函数
spark.udf.register("avgSalary" ,functions.udaf (myAverage))
spark.sql("select avgSalary(salary) from user" ).show()

// 关闭连接
spark.stop()

相关推荐
小泊客4 小时前
使用讯飞星火 Spark X1-32K 打造本地知识助手
大数据·分布式·spark·大模型应用·本地知识助手
q***23927 小时前
【SQL技术】不同数据库引擎 SQL 优化方案剖析
数据库·sql
liliangcsdn9 小时前
sql中left join和inner join的区别
数据库·sql
友善啊,朋友9 小时前
Qt:判断一个sql语句是否是select语句
sql·qt
拖拉斯旋风9 小时前
深入理解 Ajax:从原理到实战,附大厂高频面试题
前端·ajax
www_stdio9 小时前
使用 Ajax 实现异步数据请求:从原理到实践
javascript·ajax·html
武子康11 小时前
Java-169 Neo4j CQL 实战速查:字符串/聚合/关系与多跳查询
java·开发语言·数据库·python·sql·nosql·neo4j
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ11 小时前
MyBatis Plus中执行原生SQL语句方法
python·sql·mybatis
百***271112 小时前
UNION 和 UNION ALL 的区别:深入解析 SQL 中的合并操作
数据库·sql·oracle
_一两风13 小时前
深入理解 Ajax:异步 JavaScript 与 XML 的现代应用
ajax