UDF UDAF UDTF 区别
UDF
概念:
User-Defined-Function 自定义函数 、一进一出;只对单行数据产生作用;
实际使用时,UDF函数以匿名函数的形式进行操作使用
背景:
- 系统内置函数无法解决实际的业务问题,需要开发者自己编写函数实现自身的业务实现诉求。
- 应用场景非常多,面临的业务不同导致个性化实现很多,故udf很需要。
意义:
- 函数扩展得到解决,极大丰富了可定制化的业务需求。
- Input/Output要求-要解决的问题
- in:out=1:1,只能输入一条记录当中的数据,同时返回一条处理结果。
- 属于最常见的自定义函数,像cos,sin,substring,indexof等均是如此要求
实现步骤(Java创建自定义UDF类)
- 自定义一个java类
- 继承UDF类
- 重写evaluate方法
- 打包类所在项目成一个all-in-one的jar包并上传到hive所在机器
- 在hive中执行add jar操作,将jar加载到classpath中。
- 在hive中创建模板函数,使得后边可以使用该函数名称调用实际的udf函数
- hive sql中像调用系统函数一样使用udf函数
代码示例:
- 获取用户的姓名,并把首字母转换为大写字母
def main(args: Array[String]): Unit = {
// 创建上下文环境配置对象
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkSQL")
// 创建SparkSession对象
val spark: SparkSession = SparkSession.builder().config(conf).getOrCreate()
// 导包
import spark.implicits._
val rdd: RDD[(Int, String, String, Int)] = spark.sparkContext.makeRDD(
List(
(1, "zhangsan", "man", 30),
(2, "lisi", "woman", 40),
(3, "wangwu", "man", 50)
)
)
val df: DataFrame = rdd.toDF("id", "name", "gender", "age")
df.createOrReplaceTempView("user")
// UDF函数使用 : 注册函数,并以匿名函数形式进行逻辑定义
spark.udf.register("headUpper",(name:String) => {
// head方法:获取头部信息
// tail方法:获取尾部信息
name.head.toUpper + name.tail
})
spark.sql("select headUpper(name) from user").show()
// 释放资源
spark.stop()
}
输出结果:
+---------------+
|headUpper(name)|
+---------------+
| Zhangsan|
| Lisi|
| Wangwu|
+---------------+
UDAF
概念:
- User- Defined Aggregation Funcation;用户定义聚合函数,可对多行数据产生作用;
- 等同与SQL中常用的SUM(),AVG(),也是聚合函数 。
意义:
Input/Output要求-要解决的问题
- in:out=n:1,即接受输入N条记录当中的数据,同时返回一条处理结果。
- 属于最常见的自定义函数,像count,sum,avg,max等均是如此要求
实现步骤
- 自定义一个java类
- 继承UDAF类
- 内部定义一个静态类,实现UDAFEvaluator接口
- 实现方法init,iterate,terminatePartial,merge,terminate,共5个方法. 详见下图
- 在hive中执行add jar操作,将jar加载到classpath中。
- 在hive中创建模板函数,使得后边可以使用该函数名称调用实际的udf函数
- hive sql中像调用系统函数一样使用udaf函数
UDTF
概念:
User-Defined Table-Generating Functions
要解决一行输入多行输出的问题,问题的应用场景不少
用udtf解决一行输入多行输出的不多,往往被lateral view explode+udf等替代实现,比直> 接用udtf会更简单、直接一些