自定义用户函数有两种方式,区别:是否使用强类型,参考demo:https://github.com/asker124143222/spark-demo

1、不使用强类型,继承UserDefinedAggregateFunction

package com.home.spark

import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.types._ object Ex_sparkUDAF {
def main(args: Array[String]): Unit = {
val conf = new SparkConf(true).setAppName("spark udf").setMaster("local[*]")
val spark = SparkSession.builder().config(conf).getOrCreate() //自定义聚合函数
//创建聚合函数对象
val myUdaf = new MyAgeAvgFunc //注册自定义函数
spark.udf.register("ageAvg",myUdaf) //使用聚合函数
val frame: DataFrame = spark.read.json("input/userinfo.json")
frame.createOrReplaceTempView("userinfo")
spark.sql("select ageAvg(age) from userinfo").show() spark.stop()
}
} //声明自定义函数
//实现对年龄的平均,数据如:{ "name": "tom", "age" : 20}
class MyAgeAvgFunc extends UserDefinedAggregateFunction {
//函数输入的数据结构,本例中只有年龄是输入数据
override def inputSchema: StructType = {
new StructType().add("age", LongType)
} //计算时的数据结构(缓冲区)
// 本例中有要计算年龄平均值,必须有两个计算结构,一个是年龄总计(sum),一个是年龄个数(count)
override def bufferSchema: StructType = {
new StructType().add("sum", LongType).add("count", LongType)
} //函数返回的数据类型
override def dataType: DataType = DoubleType //函数是否稳定
override def deterministic: Boolean = true //计算前缓冲区的初始化,结构类似数组,这里缓冲区与之前定义的bufferSchema顺序一致
override def initialize(buffer: MutableAggregationBuffer): Unit = {
//sum
buffer(0) = 0L
//count
buffer(1) = 0L
} //根据查询结果更新缓冲区数据,input是每次进入的数据,其数据结构与之前定义的inputSchema相同
//本例中每次输入的数据只有一个就是年龄
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
if(input.isNullAt(0)) return
//sum
buffer(0) = buffer.getLong(0) + input.getLong(0) //count,每次来一个数据加1
buffer(1) = buffer.getLong(1) + 1
} //将多个节点的缓冲区合并到一起(因为spark是分布式的)
override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
//sum
buffer1(0) = buffer1.getLong(0) + buffer2.getLong(0) //count
buffer1(1) = buffer1.getLong(1) + buffer2.getLong(1)
} //计算最终结果,本例中就是(sum / count)
override def evaluate(buffer: Row): Any = {
buffer.getLong(0).toDouble / buffer.getLong(1)
}
}

2、使用强类型,

package com.home.spark

import org.apache.spark.SparkConf
import org.apache.spark.sql._
import org.apache.spark.sql.expressions.Aggregator object Ex_sparkUDAF2 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf(true).setAppName("spark udf class").setMaster("local[*]")
val spark = SparkSession.builder().config(conf).getOrCreate() //rdd转换成df或者ds需要SparkSession实例的隐式转换
//导入隐式转换,注意这里的spark不是包名,而是SparkSession的对象名
import spark.implicits._ //创建聚合函数对象
val myAvgFunc = new MyAgeAvgClassFunc
val avgCol: TypedColumn[UserBean, Double] = myAvgFunc.toColumn.name("avgAge")
val frame = spark.read.json("input/userinfo.json")
val userDS: Dataset[UserBean] = frame.as[UserBean]
//应用函数
userDS.select(avgCol).show() spark.stop()
}
} case class UserBean(name: String, age: BigInt) case class AvgBuffer(var sum: BigInt, var count: Int) //声明用户自定义函数(强类型方式)
//继承Aggregator,设定泛型
//实现方法
class MyAgeAvgClassFunc extends Aggregator[UserBean, AvgBuffer, Double] {
//初始化缓冲区
override def zero: AvgBuffer = {
AvgBuffer(0, 0)
} //聚合数据
override def reduce(b: AvgBuffer, a: UserBean): AvgBuffer = {
if(a.age == null) return b
b.sum = b.sum + a.age
b.count = b.count + 1 b
} //缓冲区合并操作
override def merge(b1: AvgBuffer, b2: AvgBuffer): AvgBuffer = {
b1.sum = b1.sum + b2.sum
b1.count = b1.count + b2.count b1
} //完成计算
override def finish(reduction: AvgBuffer): Double = {
reduction.sum.toDouble / reduction.count
} override def bufferEncoder: Encoder[AvgBuffer] = Encoders.product override def outputEncoder: Encoder[Double] = Encoders.scalaDouble
}

继承Aggregator

sparksql 自定义用户函数(UDF)的更多相关文章

  1. Sqlserver如何递归查询层级数据将父级字段和本级某个字段合并?如何自定义用户函数并调用?

    开门见山,首先说下遇到的问题:前期系统地区字典表中,每个省市县只存了本级名称,没存完整的字段.如:肥西县隶属安徽省合肥市,表中就存了一个肥西县.现有需求需要将完整字段显示,由于系统已在线上运营,无法做 ...

  2. 048 SparkSQL自定义UDAF函数

    一:程序 1.需求 实现一个求平均值的UDAF. 这里保留Double格式化,在完成求平均值后与系统的AVG进行对比,观察正确性. 2.SparkSQLUDFDemo程序 package com.sc ...

  3. Spark(十三)SparkSQL的自定义函数UDF与开窗函数

    一 自定义函数UDF 在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_ ...

  4. SparkSQL中的自定义函数UDF

    在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...

  5. Spark(十三)【SparkSQL自定义UDF/UDAF函数】

    目录 一.UDF(一进一出) 二.UDAF(多近一出) spark2.X 实现方式 案例 ①继承UserDefinedAggregateFunction,实现其中的方法 ②创建函数对象,注册函数,在s ...

  6. java mysql自定义函数UDF之调用c函数

    正如sqlite可以定义自定义函数,它是通过API定义c函数的,不像其他,如这里的mysql.sqlite提供原生接口就可以方便的调用其他语言的方法,同样的mysql也支持调用其它语言的方法. goo ...

  7. 10_Hive自定义函数UDF

    Hive官方的UDF手册地址是:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF 1.使用内置函数的快捷方法: 创 ...

  8. hive自定义函数UDF UDTF UDAF

    Hive 自定义函数 UDF UDTF UDAF 1.UDF:用户定义(普通)函数,只对单行数值产生作用: UDF只能实现一进一出的操作. 定义udf 计算两个数最小值 public class Mi ...

  9. T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst、语言版本影响!

    原文:T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst.语言版本影响! CSDN 的 Blog 太滥了!无时不刻地在坏! 开始抢救性搬家 ...

随机推荐

  1. python自动刷新抢火车票

    #!/usr/bin/env python #-*- coding: utf-8 -*- """ 火车票 可以自动填充账号密码,同时,在登录时,也可以修改账号密码 然后手 ...

  2. CDH6.3.1安装hue 报错

    x 一.查看日志server运行日志 /var/log/cloudera-scm-server/cloudera-scm-server.log 2019-12-11 17:28:34,201 INFO ...

  3. JS中字符串的常见属性及方法

    1.属性 1.1.length var txt = "abc 123"; console.log(txt.length); 2.方法 2.1.返回字符位置(indexOf()) 该 ...

  4. 【Linux】服务器间免密登录、免确认机器指纹

    1.生成密钥 ssh-keygen -t rsa -C "<填写自己方便识别的注释>" -b 4096  没什么问题就执行三次空格. 三次问题是1.填入生成密钥对的路径 ...

  5. supermarket

    题目链接 题意:给你n个商品,商品的利润和商品的过期时间,商品必须在过期时间内卖才能算利润,每天只能卖一件商品,问利润最大值. 思路:用并查集+贪心的思路,先给商品从大到小排序,然后选择过期时间的根节 ...

  6. [CSP-S模拟测试]:涂色游戏(DP+组合数+矩阵快速幂)

    题目描述 小$A$和小$B$在做游戏.他们找到了一个$n$行$m$列呈网格状的画板.小$A$拿出了$p$支不同颜色的画笔,开始在上面涂色.看到小$A$涂好的画板,小$B$觉得颜色太单调了,于是把画板擦 ...

  7. html标签内部简单加js 一维数组求最大值 最小值两个值位置和数字金字塔图形

     html标签内部,简单加js <a href=""></a><!DOCTYPE html PUBLIC "-//W3C//DTD XHTM ...

  8. yarn 国内加速,修改镜像源

    为什么慢 由于默认情况下执行 yarn 各种命令是去国外的 yarn 官方镜像源获取需要安装的具体软件信息,所以在不使用代理.不翻墙的情况下,从国内访问国外服务器的速度相对比较慢 可以通过以下命令快速 ...

  9. Python 进阶_迭代器 & 列表解析

    目录 目录 迭代器 iter 内建的迭代器生成函数 迭代器在 for 循环中 迭代器与字典 迭代器与文件 创建迭代器对象 创建迭代对象并实现委托迭代 迭代器的多次迭代 列表解析 列表解析的样例 列表解 ...

  10. WPF自定义控件(三)

    今天我们开始制作我们的按钮,主要的效果就是一个按钮正常状态.鼠标滑过.按下三态显示不同的图片. 首先我们需要给扩展按钮添加三个属性,分别是正常状态图片,鼠标滑过图片,按钮按下图片. 先贴出Button ...