Spark(十三)【SparkSQL自定义UDF/UDAF函数】
一.UDF(一进一出)
步骤
① 注册UDF函数,可以使用匿名函数。
② 在sql查询的时候使用自定义的UDF。
示例
import org.apache.spark.sql.{DataFrame, SparkSession}
/**
* @description: UDF一进一出
* @author: HaoWu
* @create: 2020年08月09日
*/
object UDF_Test {
def main(args: Array[String]): Unit = {
//创建SparkSession
val session: SparkSession = SparkSession.builder
.master("local[*]")
.appName("MyApp")
.getOrCreate()
//注册UDF
session.udf.register("addHello",(name:String) => "hello:"+name)
//读取json格式文件{"name":"zhangsan","age":20},创建DataFrame
val df: DataFrame = session.read.json("input/1.txt")
//创建临时视图:person
df.createOrReplaceTempView("person")
//查询的时候使用UDF
session.sql(
"""select
|addHello(name),
|age
|from person
|""".stripMargin).show
}
}
结果
|addHello(name)|age|
+--------------+---+
|hello:zhangsan| 20|
| hello:lisi| 30|
+--------------+---+
二.UDAF(多近一出)
spark2.X 实现方式
2.X版本:UserDefinedAggregateFunction 无类型或弱类型
步骤:
①继承UserDefinedAggregateFunction,实现其中的方法
②创建函数对象,注册函数,在sql中使用
//创建UDFA对象
val avgDemo1: Avg_UDAF_Demo1 = new Avg_UDAF_Demo1
//在spark中注册聚合函数
spark.udf.register("ageDemo1", avgDemo1)
案例
需求:实现avg()聚合函数的功能,要求结果是Double类型
代码实现
①继承UserDefinedAggregateFunction,实现其中的方法
import org.apache.spark.sql.Row
import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.types.{DoubleType, IntegerType, LongType, StructField, StructType}
/**
* @description: UDAF(多近一出):求age的平均值
* 2.X 版本继承UserDefinedAggregateFunction类,弱类型
* 非常类似累加器,aggregateByKey算子的操作,有个ZeroValue,不断将输入的值做归约操作,然后再赋值给ZeroValue
* @author: HaoWu
* @create: 2020年08月08日
*/
class Avg_UDAF_Demo1 extends UserDefinedAggregateFunction {
//聚合函数输入参数的数据类型,
override def inputSchema = StructType(StructField("age", LongType) :: Nil)
//聚合函数缓冲区中值的数据类型(sum,count)
override def bufferSchema = StructType(StructField("sum", LongType) :: StructField("count", LongType) :: Nil)
//函数返回值的数据类型
override def dataType = DoubleType
//稳定性:对于相同的输入是否一直返回相同的输出,一般都是true
override def deterministic = true
//函数缓冲区初始化,就是ZeroValue清空
override def initialize(buffer: MutableAggregationBuffer): Unit = {
//缓存区看做一个数组,将每个元素置空
//sum
buffer(0) = 0L
//count
buffer(1) = 0L
}
//更新缓冲区中的数据->将输入的值和缓存区数据合并
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
//input是Row类型,通过getXXX(索引值)取数据
if (!input.isNullAt(0)) {
val age = input.getLong(0)
buffer(0) = buffer.getLong(0) + age
buffer(1) = buffer.getLong(1) + 1
}
}
//合并缓冲区 (sum1,count1) + (sum2,count2) 合并
override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
buffer1(0) = buffer1.getLong(0) + buffer2.getLong(0)
buffer1(1) = buffer1.getLong(1) + buffer2.getLong(1)
}
//计算最终结果
override def evaluate(buffer: Row) = buffer.getLong(0).toDouble/buffer.getLong(1)
}
②创建函数对象,注册函数,在sql中使用
/**
* @description: 实现集合函数avg的功能
* @author: HaoWu
* @create: 2020年08月13日
*/
object UDAF_Test {
def main(args: Array[String]): Unit = {
//创建SparkSession
val spark: SparkSession = SparkSession.builder
.master("local[*]")
.appName("MyApp")
.getOrCreate()
//读取json格式文件{"name":"zhangsan","age":20}
val df: DataFrame = spark.read.json("input/1.txt")
//创建临时视图:person
df.createOrReplaceTempView("person")
//创建UDFA对象
val avgDemo1: Avg_UDAF_Demo1 = new Avg_UDAF_Demo1
//在spark中注册聚合函数
spark.udf.register("ageDemo1", avgDemo1)
//查询的时候使用UDF
spark.sql(
"""select
|ageDemo1(age)
|from person
|""".stripMargin).show
}
}
spark3.X实现方式
3.x版本: 认为2.X继承UserDefinedAggregateFunction的方式过时,推荐继承Aggregator ,是强类型
步骤:
①继承Aggregator [-IN, BUF, OUT],声明泛型,实现其中的方法
abstract class Aggregator[-IN, BUF, OUT]
IN: 输入的类型
BUF: 缓冲区类型
OUT: 输出的类型
②创建函数对象,注册函数,在sql中使用
//创建UDFA对象
val avgDemo2: Avg_UDAF_Demo2 = new Avg_UDAF_Demo2
//在spark中注册聚合函数
spark.udf.register("myAvg",functions.udaf(avgDemo2))
注意:2.X和3.X的注册方式不同
案例
需求:实现avg()聚合函数的功能,要求结果是Double类型
代码实现
①继承Aggregator [-IN, BUF, OUT],声明泛型,实现其中的方法
其中缓冲区数据用样例类进行封装。
MyBuffer类
/**
* 定义MyBuffer样例类
* @param sum 组数据sum和
* @param count 组的数据个数
*/
case class MyBuffer(var sum: Long, var count: Long)
自定义UDAF函数
import org.apache.spark.sql.Encoders
import org.apache.spark.sql.expressions.Aggregator
/**
* @description: UDAF(多近一出):求age的平均值
* 3.X Aggregator,强类型
* 非常类似累加器,aggregateByKey算子的操作,有个ZeroValue,不断将输入的值做归约操作,然后再赋值给ZeroValue
* @author: HaoWu
* @create: 2020年08月08日
*/
class Avg_UDAF_Demo2 extends Aggregator[Long, MyBuffer, Double] {
//函数缓冲区初始化,就是ZeroValue清空
override def zero = MyBuffer(0L, 0L)
//将输入的值和缓存区数据合并
override def reduce(b: MyBuffer, a: Long) = {
b.sum = b.sum + a
b.count = b.count + 1
b
}
//合并缓冲区
override def merge(b1: MyBuffer, b2: MyBuffer) = {
b1.sum = b1.sum + b2.sum
b1.count = b1.count + b2.count
b1
}
//计算最终结果
override def finish(reduction: MyBuffer) = reduction.sum.toDouble / reduction.count
/* scala中
常见的数据类型: Encoders.scalaXXX
自定义的类型:ExpressionEncoder[T]() 返回 Encoder[T]
样例类(都是Product类型): Encoders.product[T],返回Produce类型的Encoder!
*/
//缓存区的Encoder类型
override def bufferEncoder = Encoders.product[MyBuffer]
//输出结果的Encoder类型
override def outputEncoder = Encoders.scalaDouble
}
②创建函数对象,注册函数,在sql中使用
import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.{DataFrame, Row, SparkSession, functions}
/**
* @description: 实现集合函数avg的功能
* @author: HaoWu
* @create: 2020年08月13日
*/
object UDAF_Test {
def main(args: Array[String]): Unit = {
//创建SparkSession
val spark: SparkSession = SparkSession.builder
.master("local[*]")
.appName("MyApp")
.getOrCreate()
//读取json格式文件{"name":"zhangsan","age":20}
val df: DataFrame = spark.read.json("input/1.txt")
//创建临时视图:person
df.createOrReplaceTempView("person")
//创建UDFA对象
val avgDemo2: Avg_UDAF_Demo2 = new Avg_UDAF_Demo2
//在spark中注册聚合函数
spark.udf.register("myAvg",functions.udaf(avgDemo2))
//查询的时候使用UDF
spark.sql(
"""select
|myAvg(age)
|from person
|""".stripMargin).show
}
}
Spark(十三)【SparkSQL自定义UDF/UDAF函数】的更多相关文章
- 047 SparkSQL自定义UDF函数
一:程序部分 1.需求 Double数据类型格式化,可以给定小数点位数 2.程序 package com.scala.it import org.apache.spark.{SparkConf, Sp ...
- 【Spark篇】---SparkSQL中自定义UDF和UDAF,开窗函数的应用
一.前述 SparkSQL中的UDF相当于是1进1出,UDAF相当于是多进一出,类似于聚合函数. 开窗函数一般分组取topn时常用. 二.UDF和UDAF函数 1.UDF函数 java代码: Spar ...
- 【Spark篇】---SparkSql之UDF函数和UDAF函数
一.前述 SparkSql中自定义函数包括UDF和UDAF UDF:一进一出 UDAF:多进一出 (联想Sum函数) 二.UDF函数 UDF:用户自定义函数,user defined functio ...
- Spark 自定义函数(udf,udaf)
Spark 版本 2.3 文中测试数据(json) {"name":"lillcol", "age":24,"ip":& ...
- Spark Sql的UDF和UDAF函数
Spark Sql提供了丰富的内置函数供猿友们使用,辣为何还要用户自定义函数呢?实际的业务场景可能很复杂,内置函数hold不住,所以spark sql提供了可扩展的内置函数接口:哥们,你的业务太变态了 ...
- spark教程(18)-sparkSQL 自定义函数
sparkSQL 也允许用户自定义函数,包括 UDF.UDAF,但没有 UDTF 官方 API class pyspark.sql.UDFRegistration(sparkSession)[sour ...
- Hive 自定义函数 UDF UDAF UDTF
1.UDF:用户定义(普通)函数,只对单行数值产生作用: 继承UDF类,添加方法 evaluate() /** * @function 自定义UDF统计最小值 * @author John * */ ...
- sparksql 自定义用户函数(UDF)
自定义用户函数有两种方式,区别:是否使用强类型,参考demo:https://github.com/asker124143222/spark-demo 1.不使用强类型,继承UserDefinedAg ...
- 自定义UDF函数应用异常
自定义UDF函数应用异常 版权声明:本文为yunshuxueyuan原创文章.如需转载请标明出处: http://www.cnblogs.com/sxt-zkys/QQ技术交流群:299142667 ...
随机推荐
- 全志Linux Tina编译demoOmxVdec错误
测试裸流 Making install in demoOmxVdec make[6]: Entering directory '/home/liuxueneng/WorkCode/Homlet-Tin ...
- cm1 逆向分析
目录 cm1 逆向分析 前言 查壳分析 逆向分析 代码分析 qmemcpy分析 sub_401020函数分析 sub_401050函数分析 加密算法分析 POC代码编写 cm1 逆向分析 前言 还是先 ...
- RocketMQ源码详解 | Broker篇 · 其二:文件系统
概述 在 Broker 的通用请求处理器将一个消息进行分发后,就来到了 Broker 的专门处理消息存储的业务处理器部分.本篇文章,我们将要探讨关于 RocketMQ 高效的原因之一:文件结构的良好设 ...
- 更改mysql数据库根目录
1,查看原根目录 2,然后关闭数据库服务 3,cp -r 源根目录到目的根目录 4,修改my.cnf文件定义的根目录位置到目的根目录 5,启动数据库
- 羽夏看Win系统内核——系统调用篇
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
- 羽夏看Win系统内核——驱动篇
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
- silky微服务业务主机简介
目录 主机的概念 通用主机 web主机 业务主机类型 使用web主机构建微服务应用 使用通用主机构建微服务应用 构建具有websocket能力的微服务应用 构建网关 开源地址 在线文档 主机的概念 s ...
- PTA7-1 根据后序和中序遍历输出先序遍历
本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果. 输入格式: 第一行给出正整数N(≤30),是树中结点的个数.随后两行,每行给出N个整数,分别对应后序遍历和中序遍历结果, ...
- 基于Netty实现自定义消息通信协议(协议设计及解析应用实战)
所谓的协议,是由语法.语义.时序这三个要素组成的一种规范,通信双方按照该协议规范来实现网络数据传输,这样通信双方才能实现数据正常通信和解析. 由于不同的中间件在功能方面有一定差异,所以其实应该是没有一 ...
- CefSharp-基于C#的客户端开发框架技术栈开发全记录
CefSharp简介 源于Google官方 CefSharp用途 CefSharp开发示例 CefSharp应用--弹窗与右键 不弹出子窗体 禁用右键 CefSharp应用--High DPI问题 缩 ...