SparkSQL中的自定义函数-UDF&UDAF

一、UDF(User-Defined-Function)

用户自定义函数

1、注册UDF

udf对象 = spark.udf.register( 参数1, 参数2, 参数3)

参数1:UDF名称,可用于SQL风格

参数2:被注册成UDF的方法名

参数3:声明UDF的返回值类型

udf 对象:返回值对象,是一个 UDF对象,可用于DSL风格

//获取系统时间
val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
private val startTimeID: UserDefinedFunction = spark.udf.register("STARTTIMEID", (s: String) => {
 s + " time:"+df.format(new Date())
})

2、 DSL使用UDF函数

只能通过DataFrame进行DSL查询

ruleFrame.select(startTimeID($"API_CODE"),$"API_ID").show()

3、SparkSQL使用UDF

需要先注册成表,在进行sql查询

ruleFrame.createOrReplaceTempView("AAAS_RULE_20220316")
spark.sql("select STARTTIMEID(API_CODE),API_CODE from AAAS_RULE_20220316").show()

二、UDAF 用户自定义聚合函数

1、自定义UDAF函数类--传入类型为样例类

自定义聚合函数类:计算年龄的平均值

继承org.apache.spark.sql.expressions.Aggregator, 定义泛型

IN : 输入的数据类型 Long

BUF : 缓冲区的数据类型 Buff ->样例类

OUT : 输出的数据类型 Long

重写方法(6个)

package Util

import bean.{UDAFAgeFunction, UserInfo}
import org.apache.spark.sql.expressions.Aggregator
import org.apache.spark.sql.{Encoder, Encoders}

/**
 * 自定义聚合函数类:计算年龄的平均值
 * 1. 继承org.apache.spark.sql.expressions.Aggregator, 定义泛型
 * IN : 输入的数据类型 Long
 * BUF : 缓冲区的数据类型 Buff
 * OUT : 输出的数据类型 Long
 * 2. 重写方法(6个)
 */
class MyAvgUDAF extends Aggregator[UserInfo,UDAFAgeFunction,Long]{
	// z & zero : 初始值或零值
	// 缓冲区的初始化,需要更改入参:缓冲区UDAFAgeBuffer样例类,给个空值
	override def zero: UDAFAgeFunction = {
		UDAFAgeFunction(0L,0L)
	}
	//根据输入的数据更新缓冲区的数据,缓冲区的计算方式
	//入参:缓冲区UDAFAgeBuffer,输入数据UserInfo
	override def reduce(buffer: UDAFAgeFunction, userInfo: UserInfo): UDAFAgeFunction = {
			buffer.ageSum=buffer.ageSum+userInfo.age
			buffer.cnt=buffer.cnt+1
		buffer
	}
	//合并缓冲区,sumAge+sumAge,cnt+cnt,入参是不同缓冲区的数据
	override def merge(buffer1: UDAFAgeFunction, buffer2: UDAFAgeFunction):  UDAFAgeFunction = {
		UDAFAgeFunction(buffer1.ageSum+buffer2.ageSum,buffer1.cnt+buffer2.cnt)
	
	}
	//计算结果缓冲区合并后对缓冲区数据类型做计算,入参是缓冲区数据,返回值是计算结果,这里是平均年龄
	override def finish(buffer: UDAFAgeFunction): Long = {
		buffer.ageSum/buffer.cnt
	}
	// 缓冲区的编码操作,变更入参为缓冲区,如果是样例类就是Encoders.product,否则就是对应的scalaLon\scalaInt等类型
	override def bufferEncoder: Encoder[UDAFAgeFunction] = Encoders.product
	// 输出的编码操作,入参为计算结果(Long),如果是样例类就是Encoders.product,否则就是对应的scalaLon\scalaInt等类型
	override def outputEncoder: Encoder[Long] = Encoders.scalaLong
}

2、自定义UDAF函数类--传入类型为数据类型Int等

package Util
import bean.UDAFAgeFunction
import org.apache.spark.sql.expressions.Aggregator
import org.apache.spark.sql.{Encoder, Encoders}

/**
 * 自定义聚合函数类:计算年龄的平均值
 * 1. 继承org.apache.spark.sql.expressions.Aggregator, 定义泛型
 * IN : 输入的数据类型 Long
 * BUF : 缓冲区的数据类型 Buff
 * OUT : 输出的数据类型 Long
 * 2. 重写方法(6个)
 */
class MyAvgUDAFNew extends Aggregator[Int,UDAFAgeFunction,Long]{
	// z & zero : 初始值或零值
	// 缓冲区的初始化,需要更改入参:缓冲区UDAFAgeBuffer样例类,给个空值
	override def zero: UDAFAgeFunction = {
		UDAFAgeFunction(0L,0L)
	}
	//根据输入的数据更新缓冲区的数据,缓冲区的计算方式
	//入参:缓冲区UDAFAgeBuffer,输入数据UserInfo
	override def reduce(buffer: UDAFAgeFunction, age: Int): UDAFAgeFunction = {
			buffer.ageSum=buffer.ageSum+age
			buffer.cnt=buffer.cnt+1
		buffer
	}
	//合并缓冲区,sumAge+sumAge,cnt+cnt,入参是不同缓冲区的数据
	override def merge(buffer1: UDAFAgeFunction, buffer2: UDAFAgeFunction):  UDAFAgeFunction = {
		UDAFAgeFunction(buffer1.ageSum+buffer2.ageSum,buffer1.cnt+buffer2.cnt)
	
	}
	//计算结果缓冲区合并后对缓冲区数据类型做计算,入参是缓冲区数据,返回值是计算结果,这里是平均年龄
	override def finish(buffer: UDAFAgeFunction): Long = {
		buffer.ageSum/buffer.cnt
	}
	// 缓冲区的编码操作,变更入参为缓冲区,如果是样例类就是Encoders.product,否则就是对应的scalaLon\scalaInt等类型
	override def bufferEncoder: Encoder[UDAFAgeFunction] = Encoders.product
	// 输出的编码操作,入参为计算结果(Long),如果是样例类就是Encoders.product,否则就是对应的scalaLon\scalaInt等类型
	override def outputEncoder: Encoder[Long] = Encoders.scalaLong
}

3、二者使用中的区别

package SparkSQL.UDF

import Util.{Env, MyAvgUDAF, MyAvgUDAFNew}
import bean.UserInfo
import org.apache.log4j.{Level, Logger}
import org.apache.spark.SparkContext
import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.{Dataset, SparkSession, TypedColumn, functions}

object UDAFDemo extends App  with Env{
		/*
		* 自定义聚合函数
		* 强类型聚合函数 Aggregator
		* */
	Logger.getLogger("org").setLevel(Level.ERROR)
	
	//准备spark环境
	private val sc: SparkContext = getSparkContext()
	//准备SparkSession环境,SparkSession 是 Spark 最新的 SQL 查询起始点
	private val spark: SparkSession = getSparkSession()
	import spark.implicits._

	//创建DataSet
	private val userInfoRdd = sc.textFile("src/data/userInfo.txt").map(data=>UserInfo(
		data.split(" ")(0),data.split(" ")(1).toInt)
	)

	private val userInfoSet: Dataset[UserInfo] = userInfoRdd.toDF().as[UserInfo]
	userInfoSet.createOrReplaceTempView("userInfo")
	println("############传参为有类型的UDAF###################")
	//因为myAvgUDAFFunction传入的是样例类UserInfo,所以不需要处理select的字段,而是把整个函数当成列数据传入,直接查询结果
	//不注册 将UDAF函数转换为查询的列对象
	
	private val myAvgUDAFCol: TypedColumn[UserInfo, Long] = new MyAvgUDAF().toColumn
	println("   DSl风格结果")
	userInfoSet.select(myAvgUDAFCol).show
	println("   SQl风格不支持查询列对象")
	println("############传参为无类型的UDAF###################")
	
	//替换UDAF的入参,UserInfo改为(Int)就可以通过select myAvgUDAFFunction(name,age) from table 查询
	//注册UDAF,方式和UDF一致
	private val myAvgUDAFNew = new MyAvgUDAFNew
	private val myAvgAgeNew: UserDefinedFunction = spark.udf.register("MYAvgAgeNew", functions.udaf(myAvgUDAFNew))
	println("   DSl风格结果")
	userInfoSet.select(myAvgAgeNew($"age")).show()

	println("   sql风格结果")

	spark.sql("select MYAvgAgeNew(age) from userInfo").show()
	
	sc.stop()
	spark.stop()
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spark自定义函数包括三种类型:udfudaf和udtf。 1. udf(User-Defined Function):用户自定义函数,用于对DataFrame的每个元素进行单独的处理,返回一个新的值。可以使用Scala、Java或Python编写。 2. udaf(User-Defined Aggregate Function):用户自定义聚合函数,用于对DataFrame的一组元素进行聚合操作,返回一个新的值。可以使用Scala、Java或Python编写。 3. udtf(User-Defined Table-Generating Function):用户自定义表生成函数,用于将一行数据转换为多行数据,返回一个新的DataFrame。只能使用Scala或Java编写。 这些自定义函数可以帮助我们更好地处理数据,提高Spark的处理效率和灵活性。 ### 回答2: Spark 是大数据处理一款极为流行的计算框架,自带的函数库(UDF)非常有限,无法满足大规模数据处理需求,因此需要 Spark 自定义函数UDF)来弥补这一不足。自定义函数分为三种类型:UDFUDAF、UDTF。 UDF(User-Defined Function)即用户自定义函数,是一种对 RDD 或 DataFrame 数据进行处理的自定义函数。使用 UDF,可以用编写的代码扩展 Spark 的现有函数库,使其支持更为复杂的操作,提高工作效率。使用 UDF 可以通过嵌套 SQL 或是反射来创建一个函数。UDF 主要通过 Spark SQL 来进行使用,对于 Python 程序员来说还有 UDF 对象模型。 UDAF(User-Defined Aggregation Function)即用户自定义聚合函数。UDAF 可以更好地封装用户自定义聚合函数过程,提高代码复用率,把整个聚合过程封装到一个函数,便于调用和维护。通常使用 UDAF 构造聚合表达式并将其应用于 Spark SQL 查询。在使用聚合操作时,用户可以指定自定义函数,一般使用聚合函数配合 Spark SQL 或是 API 来使用。 UDTF(User-Defined Table-Generating Function)即用户自定义表格生成函数,可以将一个输入行拆分成多个输出行,还可以通过 UDTF 将一个输入列转化成多个输出列。UDTF 操作有助于负责多输出格式和分割的情况下,实现强大的集合任务文件解析和行转换。与 UDFUDAF 类似,UDTF 可以在调用函数时使用 Apply 函数。UDTF 可以返回多个 Row 对象,并将其转换为新的 DataFrame。UDTF 可以将一行拆分成多行,进行数据拆分和处理的任务。 总而言之,自定义函数是一个非常强大的工具,可以扩展 Spark 的能力,提高计算效率和工作效率。通过三种类型的自定义函数UDFUDAF、UDTF),Spark 可以更方便地进行数据处理和分析,使这个框架具备更灵活的应用能力。 ### 回答3: Spark是一种分布式计算框架,其生态圈非常丰富。在Spark,我们可以使用自定义函数(User Defined Function,简称UDF)、自定义聚合函数(User Defined Aggregate Function,简称UDAF)及自定义表生成函数(User Defined Table Generating Function,简称UDTF)来满足特定的需求。 UDFSpark最常用的自定义函数,特别适合对单个列或多个列进行简单转换的场景。UDF可以用Scala、Java或Python等语言来编写。在Scala或Java定义UDF时,需要定义一个函数,并将它与SparkSession的udf()方法一起使用。在PythonUDF的定义基于通用Python函数,使用Python的decorators来描述该函数的功能。 UDAF是用于聚合多个值的自定义函数UDAF的好处是可以以两种不同的方式来使用:作为聚合函数或开窗函数。Spark提供了两种UDAF:typed aggregates和untyped aggregates。typed aggregates是一种类型安全的操作,可以通过将多个值组合在一起来处理。untyped aggregates是一种无类型的操作,需要我们自己来处理所有细节。 UDTF是用于生成几个结果表的自定义函数。在使用UDTF时,我们需要定义一个新的间表来存储结果,然后将间表传递给Spark SQL的from()方法,以创建最终结果。 无论使用哪种自定义函数,我们都需要考虑性能因素。因为我们的数据通常分布在多个计算节点上,所以不合理的计算可能会导致结果不准确或性能下降。另外,我们还需要确保我们的自定义函数能够处理大型数据集,并且具有足够的容错能力。 总之,Spark自定义函数可以帮助我们实现一些常规操作以外的数据处理需求。通过UDFUDAF和UDTF,我们可以根据具体的场景设计出高效、可靠的数据处理方案。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值