自定义用户函数有两种方式,区别:是否使用强类型,参考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. cocos2D-X 打包

    { //首先有java jdk,android sdk,android ndk //用android studio  import //匹配gradle 的版本 有些gradle可能下载不下来,不用慌 ...

  2. Jmeter性能测试,使用ServerAgent监控服务端性能指标

    一.jmeter1.下载JMeter Plugins Manager.jar放到你的jmeter\lib\ext目录下2.启动jmeter,进入Plugins Manager找到perfmon安装这个 ...

  3. Hadoop编程调用HDFS(JAVA)

    1.运行环境 开发工具:intellij idea JDK版本:1.8 项目管理工具:Maven 4.0.0 Hadoop环境: Cloudera QuickStart 2.GITHUB地址 http ...

  4. 9.27-uname,useradd命令

    打印系统信息 [root@wen ~]# uname Linux [root@wen ~]# uname -r #内核版本 2.6.32-573.el6.x86_64 [root@wen ~]# un ...

  5. 分享几套bootstrap后台模板【TP5版】

    分享几套bootstrap后台模板[TP5版],模板来源于网络,需要的拿走.1.AdminLTE 链接: http://pan.baidu.com/s/1o7BXeCM 密码: zfhy 2.Boot ...

  6. CentOS 如何将.deb 文件 转换.rpm, centos安装deb包

    CentOS 如何将.deb 文件 转换.rpm [root@localhost tmp]#tar zxvf alien_8.88.tar.gz yum install alien [root@loc ...

  7. arcpy 常用操作

    目录: 通用操作 条件函数 前提: import arcpy from arcpy.sa import * 1.通用操作 设置工作路径:arcpy.env.workspace("path_o ...

  8. obj文件中的关键字

    obj文件使用的关键字 关键字 含义 v 表示本行指定一个顶点,此关键字后跟着3个单精度浮点数,分别表示该顶点的X.Y.Z坐标值 vt 表示本行指定一个纹理坐标,此关键字后跟着两个单精度浮点数,分别表 ...

  9. bootstrap基础模板页面,详细注释

    ​ <!--html5 骨架--> <!DOCTYPE html> <!--语言是中文简体--> <html lang="zh-cn"&g ...

  10. hdu3518 Boring counting(后缀数组)

    Boring counting 题目传送门 解题思路 后缀数组.枚举每种长度,对于每个字符串,记录其最大起始位置和最小起始位置,比较是否重合. 代码如下 #include <bits/stdc+ ...