sparksql 自定义用户函数(UDF)
自定义用户函数有两种方式,区别:是否使用强类型,参考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)的更多相关文章
- Sqlserver如何递归查询层级数据将父级字段和本级某个字段合并?如何自定义用户函数并调用?
开门见山,首先说下遇到的问题:前期系统地区字典表中,每个省市县只存了本级名称,没存完整的字段.如:肥西县隶属安徽省合肥市,表中就存了一个肥西县.现有需求需要将完整字段显示,由于系统已在线上运营,无法做 ...
- 048 SparkSQL自定义UDAF函数
一:程序 1.需求 实现一个求平均值的UDAF. 这里保留Double格式化,在完成求平均值后与系统的AVG进行对比,观察正确性. 2.SparkSQLUDFDemo程序 package com.sc ...
- Spark(十三)SparkSQL的自定义函数UDF与开窗函数
一 自定义函数UDF 在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_ ...
- SparkSQL中的自定义函数UDF
在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...
- Spark(十三)【SparkSQL自定义UDF/UDAF函数】
目录 一.UDF(一进一出) 二.UDAF(多近一出) spark2.X 实现方式 案例 ①继承UserDefinedAggregateFunction,实现其中的方法 ②创建函数对象,注册函数,在s ...
- java mysql自定义函数UDF之调用c函数
正如sqlite可以定义自定义函数,它是通过API定义c函数的,不像其他,如这里的mysql.sqlite提供原生接口就可以方便的调用其他语言的方法,同样的mysql也支持调用其它语言的方法. goo ...
- 10_Hive自定义函数UDF
Hive官方的UDF手册地址是:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF 1.使用内置函数的快捷方法: 创 ...
- hive自定义函数UDF UDTF UDAF
Hive 自定义函数 UDF UDTF UDAF 1.UDF:用户定义(普通)函数,只对单行数值产生作用: UDF只能实现一进一出的操作. 定义udf 计算两个数最小值 public class Mi ...
- T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst、语言版本影响!
原文:T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst.语言版本影响! CSDN 的 Blog 太滥了!无时不刻地在坏! 开始抢救性搬家 ...
随机推荐
- 如何在某个apps包下面中创建APP
- 【HDU6609】Find the answer【线段树】
题目大意:给你一个序列,对于每个i,你可以选择1~i-1中任意多的数并将它删去,剩余的数(包括i)∑≤m,问对于每个i最少删几个数可以达到要求 题解: 考虑朴素的思想,对于每个i,我只需要删去最大的若 ...
- 【Linux】grep显示匹配行的上下几行的用法
打印匹配行的前后5行 grep -5 ‘something’ file 打印匹配行的前后5行 grep -C 5 ‘something’ file 打印匹配行的后5行 grep -A 5 ‘somet ...
- ElasticSearch学习文档2018.11
1 Elasticsearch安装 1.1 ES6.0版本安装head插件 1.1 下载head插件 下载地址:https://github.com/mobz/elasticsear ...
- [CSP-S模拟测试]:tree(DP)
题目传送门(内部题57) 输入格式 第一行包含一个数:$n$表示树的节点数.接下来$n-1$行,每行包含两个数:$u,v$表示无根树的一条边. 输出格式 输出$n$行,第$i$行包含一个浮点数,保留三 ...
- 2018-2019 2 20165203 《网络对抗技术》Exp9 Web安全基础
2018-2019 2 20165203 <网络对抗技术>Exp9 Web安全基础 实验要求 本实践的目标理解常用网络攻击技术的基本原理,做不少于7个题目,共3.5分.包括(SQL,XSS ...
- Tarjan 总结
Tarjan 基础 dfn[i]: 在dfs中该节点被搜索的次序(时间戳). low[i]: 为i或i的子树能够追溯到的最早的栈中节点的次序号. 当 dfn[i] == low[i] 时,为i或i的子 ...
- codeforces 582A GCD Table
题意简述: 给定一个长度为$n$的序列 将这个序列里的数两两求$gcd$得到$n^2$个数 将这$n^2$个数打乱顺序给出 求原序列的一种可能的情况 ------------------------- ...
- 同源策略和跨域资源共享(CROS)
同源策略 Same-origin policy - Web security | MDN 跨站资源共享 Cross-Origin Resource Sharing (CORS) - HTTP | MD ...
- .net 运行原理
刚学习那会,感觉.net运行原理是很复杂的,也去了解过相关的东西,但是很晦涩,难于理解.感觉有些难了,也就放弃了解了.今天回头想想,也是当时有些毛躁了,不管怎么说,时至今日是有些明白运行原理. 从头开 ...