1. 首页 > Hadoop教程 > 正文

大数据教程FG036-Hive自定义函数UDF开发实战

内容简介:本文详细介绍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环境
java -version

# 检查Maven环境
mvn -version

# 检查Hive版本
hive –version

# Java环境
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函数部署与测试

# 上传JAR到HDFS
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 中位数聚合函数开发

# 创建中位数UDAF
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开发

# 创建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

#!/bin/bash
# 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 “=== 部署完成 ===”

=== 字符串UDF部署 ===
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分析执行计划
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

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息