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 ...
随机推荐
- 数字孪生 3D 科技馆的科学传播新模式
前言 科技馆是一种参与型体验型的博物馆,以传播科学知识.培养公众的科学创新技术为宗旨,并以其生动的展现方式得到公众的广泛欢迎.一直以来,我国科技馆的发展受到各种因素的制约和影响,发展缓慢.如今在我国经 ...
- C语言图书管理借阅系统——ncurses库的使用
一.前言 作为一只大四狗,最近还跟着大二同学修了一门课(当然不是之前没通过啦),课程是高级语言课程设计,高级语言指的是C语言 :),内容是做一个XX管理系统,我选择了图书管理系统,先介绍下我做的系统: ...
- SpringCloud 2020.0.4 系列之 Sleuth + Zipkin
1. 概述 老话说的好:安全不能带来财富,但盲目的冒险也是不可取的,大胆筹划,小心实施才是上策. 言归正传,微服务的特点就是服务多,服务间的互相调用也很复杂,就像一张关系网,因此为了更好的定位故障和优 ...
- NOIP模拟92&93(多校26&27)
前言 由于太菜了,多校26 只改出来了 T1 ,于是直接并在一起写啦~~~. T0 NOIP 2018 解题思路 第一次考场上面写三分,然而我并不知道三分无法处理不是严格单峰的情况,但凡有一个平台都不 ...
- Linux mem 2.5 Buddy 内存回收机制
文章目录 1. 简介 2. LRU 组织 2.1 LRU 链表 2.2 LRU Cache 2.3 LRU 移动操作 2.3.1 page 加入 LRU 2.3.2 其他 LRU 移动操作 3. LR ...
- 基于I2C的AHT20温湿度传感器的数据采集
关于:IC( Inter-- Integrated Circuit)总线是一种由 PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.它是由数据线SDA和时钟SCL构成的串行总线,可 ...
- Mac 下 Nginx 配置使用
安装 homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...
- oracle中是否有except函数: select * from a except select * from b
除外: oracle没有except这个关键字,这个关键字属于sqlserver ,在oracle里,他叫minus,与except是一个意思. select a.code OrgId, b.code ...
- SCTL 涅槃重生:投入 RAL 的怀抱
在<DistSQL:像数据库一样使用 Apache ShardingSphere>一文中,PMC 孟浩然为大家介绍了 DistSQL 的设计初衷和语法体系,并通过实战操作展示了一条 SQL ...
- Linux可执行文件格式-ELF结构详解
表1. ELF文件类型分类 ELF文件类型 说明 实例 Relocatable File 可重定位文件 未链接之前的ELF文件,可用于链接可执行文件或静态链接库 Linux下的".o&quo ...