自定义用户函数有两种方式,区别:是否使用强类型,参考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. 明明不太合适但是还是被用在配置文件和数据传输上的XML

    XML概述: 概念: 可扩展的标记语言. 功能: 作为数据本地存储的格式.(已淘汰)作为结构化存储的方式,不如数据库效率高.目前一部分移动设备中还在使用. 作为网络中传输数据的格式.(已淘汰)作为网络 ...

  2. C/C++ C++ 11 兰姆达

    { auto layer = Layer::create();    auto event = cocos2d::EventListenerTouchOneByOne::create();    ev ...

  3. vue项目中echarts使用渐变效果报错echarts is not defined

    解决办法:在当前单组件中在引用一次

  4. UIView的 形变属性transform

    // ViewController.m // 形变属性transform // // Created by LiuWei on 2018/4/23. // Copyright © 2018年 xxx. ...

  5. cannot access Input/output error

    ls: cannot access  Input/output errorls: cannot open directory .: Input/output error 硬盘故障,只读或只写,你可以d ...

  6. (转)springboot应用启动原理(一) 将启动脚本嵌入jar

    转:https://segmentfault.com/a/1190000013489340 Spring Boot Takes an opinionated view of building prod ...

  7. 登录成功后如何利用cookie保持登录状态

    Cookie是一种服务器发送给浏览器的一组数据,用于浏览器跟踪用户,并访问服务器时保持登录状态等功能. 通常用户登录的时候,服务器根据用户名和密码在服务器数据库中校验该用户是否正确,校验正确后则可以根 ...

  8. python深浅拷贝的理解和区分

    import copy a1 = ['s1','s2','s3'] #可变数据类型 a = [1,2,a1] b = a a1.append('s4') #浅拷贝 c = copy.copy(a) # ...

  9. JAVA中的面向对象与内存解析_1

    对象的创建和引用   必须使用new关键字创建对象. 使用对象(引用成员变量或来引用对象的成员变量. 使用对象(引用)方法(参数列表)来调用对象的方法. 同一类的每个对象有不同的成员变量存储空间. 同 ...

  10. javaScript Queue

    function Queue() { var items = []; this.enqueue = function(element) { items.push(element) } this.deq ...