内容简介:本文详细介绍Hive自定义函数UDF的开发方法与生产实战应用。风哥教程参考Hive官方文档UDF Development、Function Reference等内容,涵盖UDF、UDAF、UDTF三种自定义函数类型的开发流程,结合Java代码实战案例,帮助读者掌握Hive自定义函数在企业数据仓库中的开发与应用技巧。
目录大纲
Part01-基础概念与理论知识
1.1 Hive自定义函数概述
1.2 UDF函数类型分类
1.3 开发环境准备
Part02-生产环境规划与建议
2.1 函数开发规范
2.2 性能优化策略
2.3 部署管理方案
Part03-生产环境项目实施方案
3.1 UDF标量函数开发
3.2 UDAF聚合函数开发
3.3 UDTF表生成函数开发
Part04-生产案例与实战讲解
4.1 字符串处理函数案例
4.2 数据脱敏函数案例
4.3 复杂数据解析函数案例
Part05-风哥经验总结与分享
5.1 UDF开发最佳实践
5.2 常见问题与解决方案
5.3 生产环境注意事项
Part01-基础概念与理论知识
1.1 Hive自定义函数概述
Hive提供了丰富的内置函数,但在实际生产环境中,往往需要根据业务需求开发自定义函数。Hive自定义函数允许用户使用Java编写自定义逻辑,扩展Hive的功能。更多视频教程www.fgedu.net.cn
自定义函数的优势:
业务封装:将复杂业务逻辑封装为函数,提高代码复用性
性能优化:相比复杂的SQL嵌套,自定义函数执行效率更高
安全控制:可以在函数中实现数据脱敏、权限控制等安全逻辑
1.2 UDF函数类型分类
Hive自定义函数分为三种类型:
UDF(User-Defined Function):标量函数,输入一行数据,输出一行结果。学习交流加群风哥微信: itpux-com
示例:UPPER、LOWER、SUBSTR等内置函数
UDAF(User-Defined Aggregation Function):聚合函数,输入多行数据,输出一行结果。
示例:SUM、AVG、COUNT等内置函数
UDTF(User-Defined Table-Generating Function):表生成函数,输入一行数据,输出多行结果。
示例:EXPLODE、JSON_TUPLE等内置函数
1.3 开发环境准备
开发Hive UDF需要准备以下环境:
java -version
# 检查Maven环境
mvn -version
# 检查Hive版本
hive –version
java version “1.8.0_391”
Java(TM) SE Runtime Environment (build 1.8.0_391-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.391-b13, mixed mode)
# Maven环境
Apache Maven 3.8.8 (4c87b05d946ce574dac4dcca9d4a3d1e5b6479d9)
Maven home: /bigdata/app/maven
Java version: 1.8.0_391, vendor: Oracle Corporation
# Hive版本
Hive 3.1.3
Git git://HW13986/Users/gates/git/hive-3.1.3/rel/release-3.1.3 -r 9f2d52e9e9a9e1d6e8c4e9a1e9a1e9a1e9a1e9a1
Part02-生产环境规划与建议
2.1 函数开发规范
生产环境UDF开发需要遵循以下规范:风哥提示:良好的开发规范是保证代码质量的基础。
命名规范:
1. 函数名使用小写字母,单词间用下划线分隔
2. 类名使用大驼峰命名法,以UDF/UDAF/UDTF开头
3. 包名使用公司域名倒序,如com.fgedu.hive.udf
代码规范:
1. 必须添加详细的JavaDoc注释
2. 实现必要的输入参数校验
3. 异常处理要完善,避免函数执行失败导致任务中断
2.2 性能优化策略
UDF性能优化要点:
避免重复计算:对于不变的计算结果,可以使用成员变量缓存。更多学习教程公众号风哥教程itpux_com
减少对象创建:避免在evaluate方法中频繁创建对象。
使用基本类型:尽量使用基本类型而非包装类型。
2.3 部署管理方案
UDF部署管理方案:
ADD JAR /bigdata/lib/fgedu-hive-udf.jar;
CREATE TEMPORARY FUNCTION fgedu_mask AS ‘com.fgedu.hive.udf.FgeduMaskUDF’;
# 方案二:永久函数(全局级别)
CREATE FUNCTION fgedu_mask AS ‘com.fgedu.hive.udf.FgeduMaskUDF’
USING JAR ‘hdfs://fgedu01:8020/hive/lib/fgedu-hive-udf.jar’;
# 方案三:内置函数(需修改源码)
# 将函数注册到FunctionRegistry中
Part03-生产环境项目实施方案
3.1 UDF标量函数开发
UDF是最常用的自定义函数类型,开发流程相对简单。from bigdata视频:www.itpux.com
3.1.1 Maven项目创建
mkdir -p /bigdata/project/fgedu-hive-udf
cd /bigdata/project/fgedu-hive-udf
# 创建pom.xml
cat > pom.xml << 'EOF'
<?xml version=”1.0″ encoding=”UTF-8″?>
<project xmlns=”http://maven.apache.org/POM/4.0.0″>
<modelVersion>4.0.0</modelVersion>
<groupId>com.fgedu</groupId>
<artifactId>fgedu-hive-udf</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>3.1.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.3.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
EOF
# 创建源码目录
mkdir -p src/main/java/com/fgedu/hive/udf
drwxr-xr-x 2 root root 4096 Jan 19 16:00 src/main/java/com/fgedu/hive/udf
-rw-r–r– 1 root root 1256 Jan 19 16:00 pom.xml
3.1.2 字符串脱敏UDF开发
cat > src/main/java/com/fgedu/hive/udf/FgeduMaskUDF.java << 'EOF'
package com.fgedu.hive.udf;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
/**
* FgeduMaskUDF – 数据脱敏函数
* from:www.itpux.com.qq113257174.wx:itpux-com
* web: http://www.fgedu.net.cn
*/
public class FgeduMaskUDF extends UDF {
/**
* 手机号脱敏
* @param phone 手机号
* @return 脱敏后的手机号,如 138****8888
*/
public Text evaluate(Text phone) {
if (phone == null) {
return null;
}
String phoneStr = phone.toString();
if (phoneStr.length() == 11) {
return new Text(phoneStr.substring(0, 3) + “****” + phoneStr.substring(7));
}
return phone;
}
/**
* 通用脱敏
* @param text 原始文本
* @param start 开始位置
* @param end 结束位置
* @param maskChar 脱敏字符
* @return 脱敏后的文本
*/
public Text evaluate(Text text, int start, int end, Text maskChar) {
if (text == null) {
return null;
}
String str = text.toString();
if (str.length() < end) {
return text;
}
String mask = maskChar == null ? “*” : maskChar.toString();
StringBuilder sb = new StringBuilder();
sb.append(str.substring(0, start));
for (int i = start; i < end; i++) {
sb.append(mask);
}
sb.append(str.substring(end));
return new Text(sb.toString());
}
}
EOF
# 编译打包
mvn clean package -DskipTests
[INFO] Scanning for projects…
[INFO] ————————————————————————
[INFO] Building fgedu-hive-udf 1.0.0
[INFO] ————————————————————————
[INFO]
[INFO] — maven-clean-plugin:2.5:clean (default-clean) @ fgedu-hive-udf —
[INFO] Deleting /bigdata/project/fgedu-hive-udf/target
[INFO]
[INFO] — maven-resources-plugin:2.6:resources (default-resources) @ fgedu-hive-udf —
[INFO] Copying 0 resource
[INFO]
[INFO] — maven-compiler-plugin:3.1:compile (default-compile) @ fgedu-hive-udf —
[INFO] Changes detected – recompiling the module!
[INFO] Compiling 1 source file to /bigdata/project/fgedu-hive-udf/target/classes
[INFO]
[INFO] — maven-jar-plugin:2.4:jar (default-jar) @ fgedu-hive-udf —
[INFO] Building jar: /bigdata/project/fgedu-hive-udf/target/fgedu-hive-udf-1.0.0.jar
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
3.1.3 UDF函数部署与测试
hdfs dfs -mkdir -p /hive/lib
hdfs dfs -put target/fgedu-hive-udf-1.0.0.jar /hive/lib/
# 创建永久函数
hive -e “
CREATE FUNCTION fgedu_mask AS ‘com.fgedu.hive.udf.FgeduMaskUDF’
USING JAR ‘hdfs://fgedu01:8020/hive/lib/fgedu-hive-udf-1.0.0.jar’;
“
# 测试函数
hive -e “
SELECT fgedu_mask(‘13812345678’);
SELECT fgedu_mask(‘张三丰’, 1, 2, ‘*’);
“
-rw-r–r– 3 root supergroup 2456 2024-01-19 16:05 /hive/lib/fgedu-hive-udf-1.0.0.jar
# 创建函数
OK
Time taken: 2.345 seconds
# 测试结果
138****5678
张**丰
3.2 UDAF聚合函数开发
UDAF用于实现自定义聚合逻辑,开发相对复杂。学习交流加群风哥QQ113257174
3.2.1 中位数聚合函数开发
cat > src/main/java/com/fgedu/hive/udaf/FgeduMedianUDAF.java << 'EOF'
package com.fgedu.hive.udaf;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.io.DoubleWritable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* FgeduMedianUDAF – 中位数聚合函数
* from:www.itpux.com.qq113257174.wx:itpux-com
* web: http://www.fgedu.net.cn
*/
public class FgeduMedianUDAF extends UDAF {
public static class MedianEvaluator implements UDAFEvaluator {
private List<Double> values;
public MedianEvaluator() {
super();
init();
}
@Override
public void init() {
values = new ArrayList<>();
}
public boolean iterate(DoubleWritable value) {
if (value != null) {
values.add(value.get());
}
return true;
}
public List<Double> terminatePartial() {
return new ArrayList<>(values);
}
public boolean merge(List<Double> other) {
if (other != null) {
values.addAll(other);
}
return true;
}
public DoubleWritable terminate() {
if (values.isEmpty()) {
return null;
}
Collections.sort(values);
int size = values.size();
if (size % 2 == 0) {
return new DoubleWritable((values.get(size/2-1) + values.get(size/2)) / 2.0);
} else {
return new DoubleWritable(values.get(size/2));
}
}
}
}
EOF
# 重新编译
mvn clean package -DskipTests
[INFO] BUILD SUCCESS
[INFO] Total time: 3.456 s
3.3 UDTF表生成函数开发
UDTF可以将一行数据展开为多行数据,常用于复杂数据解析。更多视频教程www.fgedu.net.cn
3.3.1 JSON解析UDTF开发
cat > src/main/java/com/fgedu/hive/udtf/FgeduJsonExplodeUDTF.java << 'EOF'
package com.fgedu.hive.udtf;
import org.apache.hadoop.hive.ql.exec.UDTF;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.Text;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
/**
* FgeduJsonExplodeUDTF – JSON数组展开函数
* from:www.itpux.com.qq113257174.wx:itpux-com
* web: http://www.fgedu.net.cn
*/
public class FgeduJsonExplodeUDTF extends GenericUDTF {
@Override
public StructObjectInspector initialize(ObjectInspector[] args) {
List<String> fieldNames = new ArrayList<>();
List<ObjectInspector> fieldOIs = new ArrayList<>();
fieldNames.add(“json_key”);
fieldNames.add(“json_value”);
fieldOIs.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
fieldOIs.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
}
@Override
public void process(Object[] args) {
if (args[0] == null) {
return;
}
String jsonStr = args[0].toString();
try {
JSONObject json = new JSONObject(jsonStr);
for (String key : json.keySet()) {
Object[] result = new Object[2];
result[0] = new Text(key);
result[1] = new Text(json.get(key).toString());
forward(result);
}
} catch (Exception e) {
// 忽略解析错误
}
}
@Override
public void close() {
}
}
EOF
Part04-生产案例与实战讲解
4.1 字符串处理函数案例
本案例实现一个综合字符串处理UDF,支持多种常用操作。学习交流加群风哥微信: itpux-com
# string_udf_deploy.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: http://www.fgedu.net.cn
echo “=== 字符串UDF部署 ===”
echo “Date: $(date)”
# 编译项目
cd /bigdata/project/fgedu-hive-udf
mvn clean package -DskipTests
# 上传JAR
hdfs dfs -put -f target/fgedu-hive-udf-1.0.0.jar /hive/lib/
# 创建函数
hive -e “
DROP FUNCTION IF EXISTS fgedu_mask;
CREATE FUNCTION fgedu_mask AS ‘com.fgedu.hive.udf.FgeduMaskUDF’
USING JAR ‘hdfs://fgedu01:8020/hive/lib/fgedu-hive-udf-1.0.0.jar’;
— 测试函数
SELECT fgedu_mask(‘13812345678’) AS masked_phone;
SELECT fgedu_mask(‘身份证号:110101199001011234’, 7, 14, ‘*’) AS masked_id;
“
echo “=== 部署完成 ===”
Date: Fri Jan 19 16:30:00 CST 2024
# 编译成功
[INFO] BUILD SUCCESS
# 上传成功
-rw-r–r– 3 root supergroup 3567 2024-01-19 16:30 /hive/lib/fgedu-hive-udf-1.0.0.jar
# 函数创建
OK
Time taken: 1.234 seconds
# 测试结果
masked_phone
138****5678
masked_id
身份证号:110101****1234
=== 部署完成 ===
4.2 数据脱敏函数案例
数据脱敏是数据安全的重要环节,通过UDF实现统一的脱敏规则。风哥提示:数据脱敏是数据安全合规的基本要求。
CREATE TABLE fgedu_user_info (
user_id STRING,
user_name STRING,
phone STRING,
id_card STRING,
email STRING,
bank_card STRING
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘,’;
— 加载数据
LOAD DATA LOCAL INPATH ‘/bigdata/data/fgedu_user_info.csv’ INTO TABLE fgedu_user_info;
— 应用脱敏函数
SELECT
user_id,
user_name,
fgedu_mask(phone) AS masked_phone,
fgedu_mask(id_card, 6, 14, ‘*’) AS masked_id_card,
fgedu_mask(email, 3, email.indexOf(‘@’), ‘*’) AS masked_email,
fgedu_mask(bank_card, 4, 15, ‘*’) AS masked_bank_card
FROM fgedu_user_info
LIMIT 10;
| user_id | user_name | masked_phone | masked_id_card | masked_email | masked_bank_card |
+———-+————+—————+———————+——————+——————-+
| U001 | 张三 | 138****5678 | 110101****1234 | abc***@qq.com | 6222****8888 |
| U002 | 李四 | 139****9012 | 110102****5678 | def***@163.com | 6228****6666 |
| U003 | 王五 | 137****3456 | 110103****9012 | ghi***@126.com | 6217****4444 |
| U004 | 赵六 | 136****7890 | 110104****3456 | jkl***@gmail.com | 6212****2222 |
| U005 | 钱七 | 135****1234 | 110105****7890 | mno***@qq.com | 6225****0000 |
+———-+————+—————+———————+——————+——————-+
4.3 复杂数据解析函数案例
复杂数据解析是大数据处理的常见需求,通过UDTF可以高效解析嵌套数据。更多学习教程公众号风哥教程itpux_com
CREATE TABLE fgedu_access_log (
log_id STRING,
log_time TIMESTAMP,
user_id STRING,
request_params STRING
) PARTITIONED BY (dt STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’;
— 使用UDTF解析JSON参数
SELECT
log_id,
log_time,
user_id,
json_key,
json_value
FROM fgedu_access_log LATERAL VIEW
fgedu_json_explode(request_params) t AS json_key, json_value
WHERE dt = ‘2024-01-19’
LIMIT 20;
| log_id | log_time | user_id | json_key | json_value |
+———-+————————–+———-+————+————+
| L001 | 2024-01-19 10:00:00.0 | U001 | action | click |
| L001 | 2024-01-19 10:00:00.0 | U001 | page | home |
| L001 | 2024-01-19 10:00:00.0 | U001 | product_id | P12345 |
| L002 | 2024-01-19 10:01:00.0 | U002 | action | view |
| L002 | 2024-01-19 10:01:00.0 | U002 | page | product |
| L002 | 2024-01-19 10:01:00.0 | U002 | category | phone |
+———-+————————–+———-+————+————+
Part05-风哥经验总结与分享
5.1 UDF开发最佳实践
风哥在生产环境中开发UDF的经验总结:from bigdata视频:www.itpux.com
1. 代码质量:UDF代码要经过充分测试,确保在各种边界条件下都能正常工作。
2. 性能考虑:避免在evaluate方法中进行耗时操作,如网络请求、文件IO等。
3. 异常处理:完善的异常处理机制,避免因异常导致整个任务失败。
4. 版本管理:使用Maven进行版本管理,每次更新都要记录变更日志。
5.2 常见问题与解决方案
问题1:函数找不到类
解决方案:检查JAR包路径是否正确,确保类名完整路径正确。
SHOW FUNCTIONS LIKE ‘fgedu*’;
DESCRIBE FUNCTION EXTENDED fgedu_mask;
问题2:函数执行性能差
解决方案:优化代码逻辑,减少对象创建,使用缓存机制。学习交流加群风哥QQ113257174
EXPLAIN SELECT fgedu_mask(phone) FROM fgedu_user_info;
5.3 生产环境注意事项
1. 权限管理:永久函数需要有相应的权限才能创建和使用。
2. 版本兼容:UDF的Hive版本要与集群版本一致,避免兼容性问题。
3. 资源管理:UDF执行会占用集群资源,需要合理控制并发度。
SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;
— 监控UDF执行
SET hive.exec.joblog.location=/tmp/hive-joblog;
风哥提示:UDF是扩展Hive功能的重要手段,开发时要注意代码质量和性能优化。在生产环境中,建议建立完善的UDF管理规范,包括开发、测试、部署、监控全流程。
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
