Hive自定义函数简介及实践案例
摘要: Hive自定义函数简介及实践
关键词: 大数据、Hive、自定义函数
整体说明
从自定义函数的简介,到自定义函数的使用类型分类和使用周期分类,以及每种自定义函数的实践案例,解决具体的需求,简单图示如下:
一、简介
允许用户扩展 Hive 的功能,以实现特定的数据处理需求。
通过编写自定义函数,你可以添加新的聚合逻辑、转换操作或数据格式化等功能。
所有内置函数都是通过自定义函数的形式编写的,所以编写UDF时,可以参照Hive的源码。
- 依赖包
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
- 依赖包路径
org.apache.hadoop.hive.ql.udf.generic
- 引入依赖方式举例
import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFCovariance;
二、使用类型分类
2.1、UDF(标量函数)
-
定义: 用户自定义标量函数 (User-Defined Function),用于处理单个数据项并返回单个结果的函数类型,即一进一出。例如,将一个字符串转为大写字母。
-
UDF函数举例:
CONCAT:连接多个字符串。
UPPER:将字符串转为大写字母。
LOWER:将字符串转为小写字母。
TRIM:删除字符串中的空格。
SUBSTR:截取字符串的一部分。
2.2、UDAF(聚合函数)
-
定义: 用户自定义聚合函数 (User-Defined Aggregation Function),用于处理多个数据项并返回单个结果的函数类型,即多进一出。例如,计算一个列的平均值。
-
UDAF函数举例:
AVG:计算一个数值列的平均值。
SUM:计算一个数值列的总和。
MAX:计算一个数值列的最大值。
MIN:计算一个数值列的最小值。
COUNT:计算一个数值列的行数。
2.3、UDTF(表格函数)
-
定义: 用户自定义表格函数 (User-Defined Table Function),用于将一个输入转为多个输出的函数类型,即一进多出(如 lateral view explode())。例如,将一行数据拆分成多个单词。
-
UDTF函数举例:
EXPLODE:将一个数组或者一个 Map 类型的列拆分成多行。
LATERAL VIEW:将一个表格函数应用到一个查询中的每一行,产生多个输出行。
PARSE_URL:解析 URL 中的各个部分。
JSON_TUPLE:解析 JSON 格式的数据。
三、生命周期分类
-
临时函数: 加了 temporary 关键字的是临时函数,当退出系统时,这个函数也将消失,如果想要调用,需要登录后重新创建。而且临时 UDF 函数可以在任意库中调用,不受库限制。
-
永久函数: 不加 temporary 关键字的是永久函数,永久性的 UDF 函数会一直存在,不会因为退出系统而消失。但其他库想要调用永久性 UDF 函数需要在函数名前加上库名。
四、实践案例
4.1、MySQL AES + Base64 加密, UDF实现
4.1.1、需求背景
由于通过 iflydata 资产平台-数据服务 (这个模块是把 SQL 转换成 RestFul接口) 连接 MySQL 把敏感数据加密提供出去,使用了 MySQL 内部的加密方式。
后来由于引入了 Doris 数据库,去做这个数据加密共享出去的事,为了保持加密方式一致,所以需要 UDF (Doris UDF 可以直接使用 Hive UDF, 这里就演示注册到 Hive的效果)。
4.1.2、UDF 实现
- 实现JavaUtil
package com.bigdata.util;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* @author jpquan2
* @Description 字段加密,Mysql的加密方式,增加给Doris数据库使用
* @since 2024/10/30
*/
public class AesBase64EncryMysqlUtil {
public AesBase64EncryMysqlUtil() {
}
public static String encrptBase64(String data, String key) throws Exception {
final Cipher encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, generateMySQLAESKey(key, StandardCharsets.UTF_8));
byte[] encryptedBytes = encryptCipher.doFinal(data.getBytes());
return Base64.encodeBase64String(encryptedBytes);
}
/**
* 生成AES加解密用的SecretKeySpec
*
* @param key 加解密用的秘钥
* @param charset 编码设置 默认UTF-8
* @return SecretKeySpec实例
*/
public static SecretKeySpec generateMySQLAESKey(String key, Charset charset) {
try {
final byte[] finalKey = new byte[16];
int i = 0;
for (byte b : key.getBytes(charset)) {
finalKey[i++ % 16] ^= b;
}
//System.out.println(new String(finalKey));
return new SecretKeySpec