【Spark分布式内存计算框架——Spark SQL】13. 自定义UDF函数

文章介绍了SparkSQL如何使用UDF和UDAF进行数据处理,重点展示了在SQL和DSL中定义与注册UDF函数的方法,以姓名转小写为例,提供了完整代码示例。

第七章 自定义UDF函数

无论Hive还是SparkSQL分析处理数据时,往往需要使用函数,SparkSQL模块本身自带很多实现公共功能的函数,在org.apache.spark.sql.functions中。SparkSQL与Hive一样支持定义函数:UDF和UDAF,尤其是UDF函数在实际项目中使用最为广泛。

回顾Hive中自定义函数有三种类型:
第一种:UDF(User-Defined-Function) 函数

  • 一对一的关系,输入一个值经过函数以后输出一个值;
  • 在Hive中继承UDF类,方法名称为evaluate,返回值不能为void,其实就是实现一个方法;

第二种:UDAF(User-Defined Aggregation Function) 聚合函数

  • 多对一的关系,输入多个值输出一个值,通常与groupBy联合使用;

第三种:UDTF(User-Defined Table-Generating Functions) 函数

  • 一对多的关系,输入一个值输出多个值(一行变为多行);
  • 用户自定义生成函数,有点像flatMap;

目前来说Spark 框架各个版本及各种语言对自定义函数的支持:
在这里插入图片描述
在SparkSQL中,目前仅仅支持UDF函数和UDAF函数:

  • UDF函数:一对一关系;
  • UDAF函数:聚合函数,通常与group by 分组函数连用,多对一关系;

由于SparkSQL数据分析有两种方式:DSL编程和SQL编程,所以定义UDF函数也有两种方式,不同方式可以在不同分析中使用。

7.1 SQL 中使用

使用SparkSession中udf方法定义和注册函数,在SQL中使用,使用如下方式定义:
在这里插入图片描述
范例演示:将姓名转换为小写,调用String中toLowerCase方法。

// 读取JSON格式数据
val empDF: DataFrame = spark.read.json("datas/resources/employees.json")
/*
root
|-- name: string (nullable = true)
|-- salary: long (nullable = true)
*/
empDF.printSchema()
/*
+-------+------+
|name |salary|
+-------+------+
|Michael|3000 |
|Andy |4500 |
|Justin |3500 |
|Berta |4000 |
+-------+------+
*/
empDF.show(10, truncate = false)
// TODO: 定义UDF函数,在SQL中使用
spark.udf.register(
"lower_name", // 函数名称
(name: String) => name.toLowerCase
)
// 注册DataFrame为临时视图
empDF.createOrReplaceTempView("view_tmp_emp")
spark.sql(
"""
|SELECT name, lower_name(name) AS new_name FROM view_tmp_emp
""".stripMargin)
.show(10, truncate = false)

运行程序结果如下:
在这里插入图片描述

7.2 DSL 中使用

使用org.apache.sql.functions.udf函数定义和注册函数,在DSL中使用,如下方式:
在这里插入图片描述
范例演示:将姓名转换为小写,调用String中toLowerCase方法。

// TODO: 定义UDF函数,在DSL中使用
val lower_udf: UserDefinedFunction = udf(
(name: String) => name.toLowerCase
)
empDF
.select(
$"name", //
lower_udf($"name").as("new_name") //
)
.show(10, truncate = false)

运行结果与上面截图完全一致,在实际项目中依据分析使用自定义UDF函数。自定义UDF函数及使用完整范例演示代码:

import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.{DataFrame, SparkSession}
/**
* SparkSQL中定义UDF函数,两种方式,需求:将字符串转换为小写字母
*/
object SparkSQLUdf {
def main(args: Array[String]): Unit = {
// 构建SparkSession实例对象
val spark: SparkSession = SparkSession.builder()
.master("local[4]")
.appName(this.getClass.getSimpleName.stripSuffix("$"))
// TODO: 设置shuffle时分区数目
.config("spark.sql.shuffle.partitions", "4")
.getOrCreate()
// 导入隐式转换
import spark.implicits._
// 导入函数库
import org.apache.spark.sql.functions._
// 读取JSON格式数据
val empDF: DataFrame = spark.read.json("datas/resources/employees.json")
/*
root
|-- name: string (nullable = true)
|-- salary: long (nullable = true)
*/
empDF.printSchema()
/*
+-------+------+
|name |salary|
+-------+------+
|Michael|3000 |
|Andy |4500 |
|Justin |3500 |
|Berta |4000 |
+-------+------+
*/
empDF.show(10, truncate = false)
// TODO: 定义UDF函数,在SQL中使用
spark.udf.register(
"lower_name", // 函数名称
(name: String) => name.toLowerCase
)
// 注册DataFrame为临时视图
empDF.createOrReplaceTempView("view_tmp_emp")
spark.sql(
"""
|SELECT name, lower_name(name) AS new_name FROM view_tmp_emp
""".stripMargin)
.show(10, truncate = false)
println("==================================================")
// TODO: 定义UDF函数,在DSL中使用
val lower_udf: UserDefinedFunction = udf(
(name: String) => name.toLowerCase
)
empDF
.select(
$"name", //
lower_udf($"name").as("new_name") //
)
.show(10, truncate = false)
// 应用结束,关闭资源
spark.stop()
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

csdnGuoYuying

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值