Hive自定义函数案例(UDF、UDAF、UDTF)

 

目录

前提条件

背景

概念及适用场景

UDF(User-Defined Function)

概念

适用场景

UDAF(User-Defined Aggregate Function)

概念

适用场景

UDTF(User-Defined Table-Generating Function)

概念

适用场景

案例

UDF案例

UDTF案例

UDAF案例


前提条件

  • 安装好Hive,可参考:openEuler24.03 LTS下安装Hive3
  • 具备Java开发环境:JDK8、Maven3、IDEA

背景

Hive 作为大数据领域常用的数据仓库工具,提供了丰富的内置函数,但在实际业务场景中,内置函数往往无法满足复杂的计算需求。这时,Hive 的自定义函数就显得尤为重要。Hive 支持三种类型的自定义函数:UDF、UDAF 和 UDTF,本文分别介绍它们的概念和适用场景,并给出典型案例。

概念及适用场景

UDF(User-Defined Function)

概念

UDF 是最基本的自定义函数类型,用于实现 "单行进,单行出" 的处理逻辑,即对每行数据中的一个或多个输入值进行计算,返回一个结果值。

适用场景

  • 字符串处理(如格式转换、编码转换)
  • 数学计算(如自定义计算公式)
  • 日期处理(如自定义日期格式解析)

UDAF(User-Defined Aggregate Function)

概念

UDAF 即用户定义的聚合函数,用于实现 "多行进,一行出" 的处理逻辑,将一组数据经过计算后返回一个汇总结果,类似于 SQL 中的 SUM、COUNT 等内置聚合函数。

适用场景

  • 自定义统计指标(如计算中位数、众数)
  • 复杂数据聚合(如分组拼接字符串)
  • 多阶段聚合计算

UDTF(User-Defined Table-Generating Function)

概念

UDTF 是用户定义的表生成函数,实现 "单行进,多行出" 的处理逻辑,将一行数据扩展为多行或多列数据。

适用场景

  • 字符串拆分(如将逗号分隔的字符串拆分为多行)
  • 数组或集合展开(如将 JSON 数组展开为多行记录)
  • 复杂数据结构解析(如解析嵌套 JSON)

案例

UDF案例

需求:

自定义一个UDF实现计算给定基本数据类型的长度,效果如下:

hive(default)> select my_len("abcd");4

1)使用IDEA创建一个Maven工程Hive,工程名称例如:udf

2)添加依赖

<dependencies><dependency><groupId>org.apache.hive</groupId><artifactId>hive-exec</artifactId><version>3.1.3</version></dependency>
</dependencies>

添加依赖后,刷新依赖,如下

3)创建包、创建类

创建包:在src/main/java下创建org.exapmle.hive.udf包

创建类:MyUDF.java

package org.example.hive.udf;import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;/*** 我们需计算一个要给定基本数据类型的长度*/
public class MyUDF extends GenericUDF {/*** 判断传进来的参数的类型和长度* 约定返回的数据类型*/@Overridepublic ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {if (arguments.length !=1) {throw new UDFArgumentLengthException("please give me only one arg");}if (!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){throw  new UDFArgumentTypeException(1, "i need primitive type arg");}return PrimitiveObjectInspectorFactory.javaIntObjectInspector;}/*** 解决具体逻辑的*/@Overridepublic Object evaluate(DeferredObject[] arguments) throws HiveException {Object o = arguments[0].get();if(o==null){return 0;}return o.toString().length();}/*** 用于获取解释的字符串*/@Overridepublic String getDisplayString(String[] children) {return "";}
}

 4)创建临时函数

1)打成jar包上传到Linux /opt/module/hive/datas/myudf.jar

点击右侧的Maven,点开Lifecycle,按Ctrl键不放,同时选中clean和package,点击箭头指向的三角形图标运行

 看到BUILD SUCCESS说明打包成功,同时看到jar包所在路径,如下

将jar包上传到Linux合适目录下,例如:/home/liang/testjar

[liang@node2 testjar]$ ls
udf-1.0-SNAPSHOT.jar

(2)将jar包添加到hive的classpath,临时生效

hive (default)> add jar /home/liang/testjar/udf-1.0-SNAPSHOT.jar;

 (3)创建临时函数与开发好的java class关联

hive (default)> create temporary function my_len as "org.exapmle.hive.udf.MyUDF";

注意:创建临时函数,此时只是在当前会话生效,关闭会话,临时函数被删除。如果需要能在其他会话能看到,且关闭会话后,不删除自定义函数,则需要创建永久函数。

(4)查询函数

hive (default)> show functions;
...
months_between
murmur_hash
my_len
named_struct
negative
...
Time taken: 0.024 seconds, Fetched: 291 row(s)

看到my_len函数,说明可以使用自定义函数了。 

(5)使用自定义的临时函数

hive (default)> select my_len("abcd");

结果为

4

(6)删除临时函数

使用如下语句或者关闭会话(退出Hive命令行)删除临时函数。

hive (default)> drop temporary function my_len;

5)创建永久函数

(1)创建永久函数

把jar包上传到hdfs

[liang@node2 ~]$ hdfs dfs -put /home/liang/testjar/udf-1.0-SNAPSHOT.jar /

创建永久函数

hive (default)> 
create function my_len2 as "org.exapmle.hive.udf.MyUDF" using jar "hdfs://node2:8020/udf-1.0-SNAPSHOT.jar";

操作过程

hive (default)> create function my_len2 as "org.exapmle.hive.udf.MyUDF" using jar "hdfs://node2:8020/udf-1.0-SNAPSHOT.jar";
Added [/tmp/944c050b-e360-48f1-b7b6-93f8fd7e2644_resources/udf-1.0-SNAPSHOT.jar] to class path
Added resources: [hdfs://node2:8020/udf-1.0-SNAPSHOT.jar]
OK
Time taken: 0.212 seconds

查看函数

hive (default)> show functions;
...
dayofweek
decode
default.my_len2
degrees
dense_rank
...
Time taken: 0.019 seconds, Fetched: 291 row(s)

看到永久函数名为库名.函数名。

注意:永久函数创建的时候,在函数名之前需要自己加上库名,如果不指定库名的话,会默认把当前库的库名给加上。

退出hive命令行会话,重新进入hive命令行,再次查看函数,还可以看到default.my_len2

hive (default)> show functions;
...
dayofweek
decode
default.my_len2
degrees
dense_rank
...
Time taken: 0.019 seconds, Fetched: 291 row(s)

使用永久函数

hive (default)> select my_len2("abcd");

结果为

4

(3)删除永久函数

hive (default)> drop function my_len2;

注意:永久函数使用的时候,在其他库里面使用的话加上,库名.函数名。

UDTF案例

需求:

将字符串按分隔符分割为多行,例如:将a,b,c按照,进行分隔,得到三行

a
b
c

代码

package org.exapmle.hive.udtf;import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
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.StructField;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableStringObjectInspector;
import org.apache.hadoop.io.Text;import java.util.Arrays;
import java.util.List;@Description(name = "explode_string",value = "将字符串按分隔符分割为多行",extended = "SELECT explode_string('a,b,c', ',') FROM table_name;"
)
public class ExplodeWordsUDTF extends GenericUDTF {private WritableStringObjectInspector inputOI;private WritableStringObjectInspector separatorOI;private final Object[] forwardObj = new Object[1];private final Text outputText = new Text();@Overridepublic StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {// 获取输入参数的ObjectInspectorList<? extends StructField> inputFields = argOIs.getAllStructFieldRefs();// 检查参数数量if (inputFields.size() != 2) {throw new UDFArgumentLengthException("explode_string需要两个参数: 字符串和分隔符");}// 检查参数类型ObjectInspector firstOI = inputFields.get(0).getFieldObjectInspector();ObjectInspector secondOI = inputFields.get(1).getFieldObjectInspector();if (!(firstOI instanceof WritableStringObjectInspector) || !(secondOI instanceof WritableStringObjectInspector)) {throw new UDFArgumentLengthException("参数必须是字符串类型");}inputOI = (WritableStringObjectInspector) firstOI;separatorOI = (WritableStringObjectInspector) secondOI;// 定义输出结构List<String> fieldNames = Arrays.asList("element");List<ObjectInspector> fieldOIs = Arrays.asList(PrimitiveObjectInspectorFactory.writableStringObjectInspector);return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);}@Overridepublic void process(Object[] args) throws HiveException {if (args[0] == null) {return;}Text input = inputOI.getPrimitiveWritableObject(args[0]);Text sep = separatorOI.getPrimitiveWritableObject(args[1]);String separator = sep != null ? sep.toString() : ",";String inputStr = input.toString();// 处理空字符串if (inputStr.isEmpty()) {outputText.set("");forwardObj[0] = outputText;forward(forwardObj);return;}// 使用正则表达式分隔字符串String[] elements = inputStr.split(separator, -1);for (String element : elements) {outputText.set(element);forwardObj[0] = outputText;forward(forwardObj);}}@Overridepublic void close() throws HiveException {}
}

打jar包,上传到Linux

注册与使用

hive (default)> ADD JAR /home/liang/testjar/udf-1.0-SNAPSHOT.jar;
Added [/home/liang/testjar/udf-1.0-SNAPSHOT.jar] to class path
Added resources: [/home/liang/testjar/udf-1.0-SNAPSHOT.jar]hive (default)> CREATE TEMPORARY FUNCTION explode_string AS 'org.exapmle.hive.udtf.ExplodeStringUDTF';
OK
Time taken: 0.362 secondshive (default)> SELECT explode_string('a,b,c', ',');
OK
element
a
b
c
Time taken: 2.844 seconds, Fetched: 3 row(s)hive (default)> SELECT explode_string('hello,world', ',');
OK
element
hello
world
Time taken: 0.209 seconds, Fetched: 2 row(s)

UDAF案例

需求:

计算加权平均值,加权平均数=(Σ(数值×权重))/Σ权重

例如:

计算学生综合成绩时,若数学(学分4分,成绩90)和语文(学分3分,成绩80),其中数值为成绩,权重为学分,则加权平均成绩为 (4×90+3×80)/(4+3)≈85.71(4×90+3×80)/(4+3)≈85.71分。

代码

package org.exapmle.hive.udaf;import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.Writable;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;@Description(name = "weighted_avg",value = "计算加权平均值",extended = "SELECT weighted_avg(score, credit) FROM grades GROUP BY student_id;"
)
public class WeightedAverageUDAF extends UDAF {public static class WeightedAverageEvaluator implements UDAFEvaluator {// 存储中间结果private double sumWeightedValues;private double sumWeights;private boolean empty;@Overridepublic void init() {sumWeightedValues = 0;sumWeights = 0;empty = true;}// 处理输入行public boolean iterate(DoubleWritable value, DoubleWritable weight) {if (value == null || weight == null || weight.get() <= 0) {return true;}sumWeightedValues += value.get() * weight.get();sumWeights += weight.get();empty = false;return true;}// 存储部分结果的类public static class PartialResult implements Writable {double sumWeightedValues;double sumWeights;@Overridepublic void write(DataOutput out) throws IOException {out.writeDouble(sumWeightedValues);out.writeDouble(sumWeights);}@Overridepublic void readFields(DataInput in) throws IOException {sumWeightedValues = in.readDouble();sumWeights = in.readDouble();}}// 返回部分结果public PartialResult terminatePartial() {if (empty) {return null;}PartialResult result = new PartialResult();result.sumWeightedValues = sumWeightedValues;result.sumWeights = sumWeights;return result;}// 合并部分结果public boolean merge(PartialResult other) {if (other == null) {return true;}sumWeightedValues += other.sumWeightedValues;sumWeights += other.sumWeights;empty = false;return true;}// 返回最终结果public DoubleWritable terminate() {if (empty || sumWeights <= 0) {return null;}return new DoubleWritable(sumWeightedValues / sumWeights);}}
}

打jar包,上传到Linux

注册

hive (default)> ADD JAR /home/liang/testjar/udf-1.0-SNAPSHOT.jar;
Added [/home/liang/testjar/udf-1.0-SNAPSHOT.jar] to class path
Added resources: [/home/liang/testjar/udf-1.0-SNAPSHOT.jar]hive (default)> CREATE TEMPORARY FUNCTION weighted_avg AS 'org.exapmle.hive.udaf.WeightedAverageUDAF';
OK
Time taken: 0.043 seconds

使用

WITH grades AS (SELECT 1 AS student_id, 'Math' AS course, 90 AS score, 4 AS creditUNION ALLSELECT 1, 'English', 85, 3UNION ALLSELECT 2, 'Math', 88, 4UNION ALLSELECT 2, 'English', 92, 3
)
SELECT student_id,weighted_avg(score, credit) AS gpa
FROM grades
GROUP BY student_id;

操作过程

hive (default)> WITH grades AS (>     SELECT 1 AS student_id, 'Math' AS course, 90 AS score, 4 AS credit>     UNION ALL>     SELECT 1, 'English', 85, 3>     UNION ALL>     SELECT 2, 'Math', 88, 4>     UNION ALL>     SELECT 2, 'English', 92, 3> )> SELECT>     student_id,>     weighted_avg(score, credit) AS gpa> FROM grades> GROUP BY student_id;
Query ID = liang_20250521165046_6335eb21-2d92-4ae1-b30c-511bcb9a98ab
Total jobs = 1
Launching Job 1 out of 1
Number of reduce tasks not specified. Estimated from input data size: 1
In order to change the average load for a reducer (in bytes):set hive.exec.reducers.bytes.per.reducer=<number>
In order to limit the maximum number of reducers:set hive.exec.reducers.max=<number>
In order to set a constant number of reducers:set mapreduce.job.reduces=<number>
Starting Job = job_1747808931389_0001, Tracking URL = http://node3:8088/proxy/application_1747808931389_0001/
Kill Command = /opt/module/hadoop-3.3.4/bin/mapred job  -kill job_1747808931389_0001
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1
2025-05-21 16:51:04,388 Stage-1 map = 0%,  reduce = 0%
2025-05-21 16:51:12,756 Stage-1 map = 100%,  reduce = 0%, Cumulative CPU 3.89 sec
2025-05-21 16:51:28,486 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 11.36 sec
MapReduce Total cumulative CPU time: 11 seconds 360 msec
Ended Job = job_1747808931389_0001
MapReduce Jobs Launched:
Stage-Stage-1: Map: 1  Reduce: 1   Cumulative CPU: 11.36 sec   HDFS Read: 12918 HDFS Write: 151 SUCCESS
Total MapReduce CPU Time Spent: 11 seconds 360 msec
OK
student_id      gpa
1       87.85714285714286
2       89.71428571428571
Time taken: 43.272 seconds, Fetched: 2 row(s)

更多Hive自定义函数用法,请参考:Hive官方文档

完成!enjoy it!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言的原子操作

当我们想要对某个变量并发安全的修改&#xff0c;除了使用官方提供的mutex&#xff0c;还可以使用sync/atomic包的原子操作&#xff0c;它能够保证对变量的读取或修改期间不被其他的协程所影响。 Golang提供的原子操作都是非侵入式的&#xff0c;由标准库sync/atmoic包提供&am…

QNAP MEMOS 域名访问 SSL(Lucky)

注意&#xff1a;下述是通过ssh、docker-compose方式安装docker的&#xff0c;不是直接在container station中安装的哈&#xff01;&#xff01;&#xff01; 一、编辑docker-compose.yml文件 用“#”号标识的&#xff0c;在保存文件的时候建议去掉&#xff0c;不然有时候会出…

C#实现远程锁屏

前言 这是一次提前下班没有锁屏进而引发的一次思考后的产物&#xff0c;思考的主要场景是当人离开电脑后&#xff0c;怎么能控制电脑锁屏&#xff0c;避免屏幕上的聊天记录被曝光。 首先想到通过系统的电源计划设置闲置超时时间熄屏&#xff0c;这可能是最接近场景的解决方案&a…

[Protobuf]常见数据类型以及使用注意事项

[Protobuf]常见数据类型以及使用注意事项 水墨不写bug 文章目录 一、基本数据类型1、字段2、字段的修饰规则 二、自定义数据类型1、message类型2、enum类型3、Any类型4、oneof类型5、map类型 三、小工具1.hexdump2.decode 四、注意事项 一、基本数据类型 protobuf 支持多种基础…

JS分支和循环

程序的执行顺序 在程序开发中&#xff0c;程序有三种不同的执行顺序 1.顺序执行 2.分支执行 3.循环执行 程序的代码块 <script>//一个代码块{var num11var num22var num3num1num2}//一个休想var info{name:"chen",age:18} 1.if分支语句&#xff08;单分支语句&…

Android 开发 Kotlin 全局大喇叭与广播机制

在 Android 开发中&#xff0c;广播机制就像一个神通广大的 “消息快递员”&#xff0c;承担着在不同组件间传递信息的重任。Kotlin 语言的简洁优雅更使其在广播机制的应用中大放异彩。今天&#xff0c;就让我们一同深入探索 Android 开发中 Kotlin 全局大喇叭与广播机制的奥秘…

rabbitmq AI复习

RabbitMq rabbitmq &#x1f9d1;‍&#x1f4bb; User 帮我复习rabbitmq相关知识&#xff0c;我是一个经验丰富的程序员 &#x1f916; Assistant 好的&#xff01;很高兴能通过这种方式帮你复习或学习 RabbitMQ 的知识。按照你说的流程&#xff0c;我们从完全零基础开始&…

计算机视觉---YOLOv5

YOLOv5理论讲解 一、YOLOv5 整体架构解析 YOLOv5 延续了 YOLO 系列的 单阶段目标检测框架&#xff0c;包含 主干网络&#xff08;Backbone&#xff09;、颈部网络&#xff08;Neck&#xff09; 和 检测头&#xff08;Head&#xff09;&#xff0c;但在结构设计上更注重 轻量化…

C++多重继承详解与实战解析

#include <iostream> using namespace std; //基类&#xff0c;父类 class ClassA { public:void displayA() {std::cout << "Displaying ClassA" << std::endl;}void testFunc(){std::cout << "testFunc ClassA" << std::e…

单细胞注释前沿:CASSIA——无参考、可解释、自动化细胞注释的大语言模型

细胞类型注释是单细胞RNA-seq分析的重要步骤&#xff0c;目前有许多注释方法。大多数注释方法都需要计算和特定领域专业知识的结合&#xff0c;而且经常产生不一致的结果&#xff0c;难以解释。大语言模型有可能在减少人工输入和提高准确性的同时扩大可访问性&#xff0c;但现有…

STM32Cubemx-H7-17-麦克纳姆轮驱动

前言 --末尾右总体的.c和.h 本篇文章把麦克纳姆轮的代码封装到.c和.h&#xff0c;使用者只需要根据轮子正转的方向&#xff0c;在.h处修改定义方向引脚&#xff0c;把轮子都统一正向后&#xff0c;后面的轮子驱动就可以正常了&#xff0c;然后直接调用函数驱动即可。 设置满…

文档核心结构优化(程序C++...)

文档核心结构优化 一、文档核心结构优化二、C关键特性详解框架2.1 从C到C的范式迁移 三、深度代码解析模板3.1 现代C特性分层解析 四、C vs C 关键差异矩阵五、交互式文档设计策略5.1 三维学习路径5.2 代码缺陷互动区 六、现代C特性演进图七、性能优化可视化呈现&#xff08;深…

PyTorch ——torchvision数据集使用

如果下载的很慢&#xff0c;可以试试下面这个

纯前端实现图片伪3D视差效果

作者&#xff1a;vivo 互联网前端团队- Su Ning 本文通过depth-anything获取图片的深度图&#xff0c;同时基于pixi.js&#xff0c;通过着色器编程&#xff0c;实现了通过深度图驱动的伪3D效果。该方案支持鼠标/手势与手机陀螺仪双模式交互&#xff0c;在保证性能的同时&#x…

英语写作中“专注于”focus on、concentrate的用法

Focus on在论文写作中常用&#xff0c;指出研究点&#xff0c;例如&#xff1a; There are three approaches to achieving ID authentication. Our study will focus on ……&#xff08;有三种途径实现身份认证&#xff0c;我们的研究专注于……&#xff09; concentrate &…

go环境配置

下载对应版本的 go 版本 https://go.dev/dl/ 配置 vim ~/.zshrc export GOROOT/usr/local/go export PATH$PATH:$GOROOT/binsource ~/.zshrc >>>>>> go versiongoland 配置&#xff1a; &#x1f50d; 一、什么是GOPATH&#xff1f; GOPATH 是旧的项目结…

AI Agent智能体:底层逻辑、原理与大模型关系深度解析·优雅草卓伊凡

AI Agent智能体&#xff1a;底层逻辑、原理与大模型关系深度解析优雅草卓伊凡 一、AI Agent的底层架构与核心原理 1.1 AI Agent的基本构成要素 AI Agent&#xff08;人工智能代理&#xff09;是一种能够感知环境、自主决策并执行行动的智能系统。其核心架构包含以下关键组件…

【手搓一个原生全局loading组件解决页面闪烁问题】

页面闪烁效果1 页面闪烁效果2 封装一个全局loading组件 class GlobalLoading extends HTMLElement {constructor() {super();this.attachShadow({ mode: open });}connectedCallback() {this.render();this.init();}render() {this.shadowRoot.innerHTML <style>.load…

unix/linux source 命令,其高级使用

就像在物理学中,掌握了基本定律后,我们可以开始研究更复杂的系统和现象,source 的高级用法也是建立在对其基本行为深刻理解之上的。 让我们一起探索 source 的高级应用领域: 1. 条件化加载 (Conditional Sourcing) 根据某些条件来决定是否 source 一个文件,或者 source…

DexGarmentLab 论文翻译

单个 专家 演示 装扮 15 任务 场景 2500+ 服装 手套 棒球帽 裤子 围巾 碗 帽子 上衣 外套 服装-手部交互 捕捉 摇篮 夹紧 平滑 任务 ...... 投掷 悬挂 折叠 ... 多样化位置 ... 多样化 变形 ... 多样化服装形状 类别级 一般化 类别级(有或没有变形) 服装具有相同结构 变形 生…