Hive 之 UDF 运用(包会的)

文章目录

    • UDF 是什么?
    • reflect
      • 静态方法调用
      • 实例方法调用
    • 自定义 UDF(GenericUDF)
      • 1.创建项目
      • 2.创建类继承 UDF
      • 3.数据类型判断
      • 4.编写业务逻辑
      • 5.定义函数描述信息
      • 6.打包与上传
      • 7.注册 UDF 函数并测试
      • 返回复杂的数据类型

UDF 是什么?

Hive 中的 UDF 其实就是用户自定义函数,允许用户注册使用自定义的逻辑对数据进行处理,丰富了Hive 对数据处理的能力。

UDF 负责完成对数据一进一出处理的操作,和 Hive 中存在的函数 yearmonthday 等相同。

reflect

在 Hive 中,可以使用 reflect() 方法通过 Java 反射机制调用 Java 类的方法。

通俗来说,它可以调用 Hive 中不存在,但是 JDK 中拥有的方法。

语法

  • reflect() 函数的语法为:reflect(class,method[,arg1[,arg2..]])

静态方法调用

假设当前在 Java 中存在类如下:

package com.example;public class MathUtils {public static int addNumbers(int a, int b) {return a + b;}
}

那么使用 reflect() 方法调用时,如下所示:

SELECT reflect("com.example.MathUtils", "addNumbers", 3, 5) AS result;

注意! 这里的类 "com.example.MathUtils" 并不是在 JDK 中真实存在的,只是我作为说明的一个案例, reflect() 方法只能调用 JDK 中(原生内置)存在的方法。

所以当你需要使用 reflect() 方法时,需要先去查找调用的目标方法全类名、方法名以及是否需要传递参数。

实例方法调用

当我们需要调用 Java 中的实例方法时,先创建 Java 对象,然后再调用其方法。

例如:将乱码的字符串进行解析。

SELECT reflect('java.net.URLDecoder', 'decode', "Mozilla/5.0%20(compatible;%20MJ12bot/v1.4.7;%20http://www.majestic12.co.uk/bot.php?+)
" ,'utf-8') as result;

结果输出如下:

在这里插入图片描述

自定义 UDF(GenericUDF)

Hive 支持两种 UDF 函数自定义操作,分别是:

  • GenericUDF(通用UDF):用于实现那些可以处理任意数据类型的函数。它们的输入和输出类型可以是任意的,但需要在函数内部处理类型转换和逻辑,可以实现更复杂的逻辑处理。

  • UDF:用于实现那些只能处理特定数据类型的函数。每个 UDF 都明确指定了输入参数的类型和返回值类型,使用更为简单。

本文采用的是通用 UDF —— GenericUDF 实现方法

这里通过一个在 Hive 中实现两数相加的自定义 UDF 案例来进行说明,看完你就会啦,轻松拿捏。

1.创建项目

在 IDEA 中创建一个 Maven 项目,引入 Hive 依赖,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.jsu</groupId><artifactId>MyUDF</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!-- hive-exec依赖无需打到jar包,故scope使用provided--><dependency><groupId>org.apache.hive</groupId><artifactId>hive-exec</artifactId><version>3.1.3</version><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.0.0</version><configuration><!--将依赖编译到jar包中--><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration><executions><!--配置执行器--><execution><id>make-assembly</id><!--绑定到package执行周期上--><phase>package</phase><goals><!--只运行一次--><goal>single</goal></goals></execution></executions></plugin></plugins></build></project>

注意,引入的 Hive 依赖版本请保持和你集群中使用的版本一致。

2.创建类继承 UDF

创建一个类,我这里取名为 AddTest,继承 Hive UDF 父类 GenericUDF,需要重写三个方法,如下所示:

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
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;public class AddTest extends GenericUDF {@Overridepublic ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {return null;}@Overridepublic Object evaluate(DeferredObject[] deferredObjects) throws HiveException {return null;}@Overridepublic String getDisplayString(String[] strings) {return null;}
}
  • initialize(ObjectInspector[] objectInspectors) 方法
    这个方法是在 UDF 初始化时调用的。它用于执行一些初始化操作,并且可以用来验证 UDF 的输入参数类型是否正确。参数 objectInspectors 是一个包含输入参数的 ObjectInspector 数组,它描述了每个输入参数的类型和结构。
    一般在这个方法中检查输入参数的数量和类型是否满足你的函数的要求。如果输入参数不符合预期,你可以抛出 UDFArgumentException 异常。如果一切正常,你需要返回一个合适的 ObjectInspector 对象,它描述了你的函数返回值的类型。

  • evaluate(DeferredObject[] deferredObjects) 方法
    在这个方法中定义真正执行 UDF 逻辑的地方,获取输入的参数,并且根据输入参数执行相应的计算或操作。参数 deferredObjects 是一个包含输入参数的 DeferredObject 数组,你可以通过它来获取实际的输入值。

  • getDisplayString(String[] strings) 方法
    这个方法用于描述 UDF 的信息,用于生成可读的查询执行计划(Explain),以便用户了解查询的结构和执行过程。

3.数据类型判断

实现 UDF 的第一步操作就是在 initialize 方法中,判断用户输入的参数是否合法,出现错误时,进行反馈。

在这里主要分为三个步骤:

  1. 检验参数个数

  2. 检查参数类型

  3. 定义函数返回值类型

一般情况下,可以使用下面的模板:

    @Overridepublic ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {// 1.校验参数个数if (objectInspectors.length != 2) {throw new UDFArgumentException("参数个数有误!");}// 2.检查第1个参数是否是int类型// 判断第1个参数的基本类型ObjectInspector num1 = objectInspectors[0];if (num1.getCategory() != ObjectInspector.Category.PRIMITIVE) {throw new UDFArgumentException("第1个参数不是基本数据类型");}// 第1个参数类型判断PrimitiveObjectInspector temp = (PrimitiveObjectInspector) num1;if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp.getPrimitiveCategory()) {throw new UDFArgumentException("第1个参数应为INT类型");}// 2.检查第2个参数是否是int类型// 判断第2个参数的基本类型ObjectInspector num2 = objectInspectors[1];if (num2.getCategory() != ObjectInspector.Category.PRIMITIVE) {throw new UDFArgumentException("第2个参数不是基本数据类型");}// 第2个参数类型判断PrimitiveObjectInspector temp2 = (PrimitiveObjectInspector) num2;if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp2.getPrimitiveCategory()) {throw new UDFArgumentException("第2个参数应为INT类型");}// 3.设置函数返回值类型(返回一个整型数据)return PrimitiveObjectInspectorFactory.javaIntObjectInspector;}

4.编写业务逻辑

evaluate 方法中定义业务逻辑,这里比较简单,就是实现两数相加。

    @Overridepublic Object evaluate(DeferredObject[] deferredObjects) throws HiveException {// 完成两数相加的逻辑计算int num1 = Integer.parseInt(deferredObjects[0].get().toString());int num2 = Integer.parseInt(deferredObjects[1].get().toString());return num1 + num2;}

5.定义函数描述信息

getDisplayString 方法中定义函数在 Explain 中的描述信息,一般都是固定写法,如下所示:

    @Overridepublic String getDisplayString(String[] strings) {return getStandardDisplayString("AddTest", strings);}

把对应的函数名称进行替换即可。

6.打包与上传

对编写的项目进行打包,并上传到 HDFS 上

在这里插入图片描述

本案例的完整代码如下所示:

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
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.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;public class AddTest extends GenericUDF {@Overridepublic ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {// 1.校验参数个数if (objectInspectors.length != 2) {throw new UDFArgumentException("参数个数有误!");}// 2.检查第1个参数是否是int类型// 判断第1个参数的基本类型ObjectInspector num1 = objectInspectors[0];if (num1.getCategory() != ObjectInspector.Category.PRIMITIVE) {throw new UDFArgumentException("第1个参数不是基本数据类型");}// 第1个参数类型判断PrimitiveObjectInspector temp = (PrimitiveObjectInspector) num1;if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp.getPrimitiveCategory()) {throw new UDFArgumentException("第1个参数应为INT类型");}// 2.检查第2个参数是否是int类型// 判断第2个参数的基本类型ObjectInspector num2 = objectInspectors[1];if (num2.getCategory() != ObjectInspector.Category.PRIMITIVE) {throw new UDFArgumentException("第2个参数不是基本数据类型");}// 第2个参数类型判断PrimitiveObjectInspector temp2 = (PrimitiveObjectInspector) num2;if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp2.getPrimitiveCategory()) {throw new UDFArgumentException("第2个参数应为INT类型");}// 3.设置函数返回值类型(返回一个整型数据)return PrimitiveObjectInspectorFactory.javaIntObjectInspector;}@Overridepublic Object evaluate(DeferredObject[] deferredObjects) throws HiveException {// 完成两数相加的逻辑计算int num1 = Integer.parseInt(deferredObjects[0].get().toString());int num2 = Integer.parseInt(deferredObjects[1].get().toString());return num1 + num2;}@Overridepublic String getDisplayString(String[] strings) {return getStandardDisplayString("AddTest", strings);}}

7.注册 UDF 函数并测试

进入 Hive 中对创建的 UDF 函数进行注册。

如果你期间修改了 JAR 包并重新上传,则需要重启与 Hive 的连接,建立新的会话才会生效。

-- 永久注册
create function testAdd as 'AddTest' using jar 'hdfs://hadoop201:8020/test/MyUDF-1.0-SNAPSHOT-jar-with-dependencies.jar';-- 删除注册的函数
drop function if exists testAdd;
  • testAdd:注册的 UDF 函数名称。

  • as 'AddTest':编写的 UDF 函数全类名。

  • using jar:指定 JAR 包的全路径。

注册成功后,如下所示:

在这里插入图片描述

测试

select testAdd(1,2);

在这里插入图片描述

如果输入错误的数据类型,会进行报错提示:

在这里插入图片描述

返回复杂的数据类型

在更多的场景下,我们可能有多个返回值,那么该如何定义与配置呢?

这里还是通过上面的两数相加的案例来进行说明,套下面的模板使用:

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
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.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;import java.util.ArrayList;public class AddTestReturnList extends GenericUDF {@Overridepublic ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {// 1.校验参数个数if (objectInspectors.length != 2) {throw new UDFArgumentException("参数个数有误!");}// 2.检查第1个参数是否是int类型// 判断第1个参数的基本类型ObjectInspector num1 = objectInspectors[0];if (num1.getCategory() != ObjectInspector.Category.PRIMITIVE) {throw new UDFArgumentException("第1个参数不是基本数据类型");}// 第1个参数类型判断PrimitiveObjectInspector temp = (PrimitiveObjectInspector) num1;if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp.getPrimitiveCategory()) {throw new UDFArgumentException("第1个参数应为INT类型");}// 2.检查第2个参数是否是int类型// 判断第2个参数的基本类型ObjectInspector num2 = objectInspectors[1];if (num2.getCategory() != ObjectInspector.Category.PRIMITIVE) {throw new UDFArgumentException("第2个参数不是基本数据类型");}// 第2个参数类型判断PrimitiveObjectInspector temp2 = (PrimitiveObjectInspector) num2;if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp2.getPrimitiveCategory()) {throw new UDFArgumentException("第2个参数应为INT类型");}// 3.设置函数返回值类型(返回一个键值对数据)ArrayList<String> structFieldNames = new ArrayList<>();ArrayList<ObjectInspector> structFieldObjectInspectors = new ArrayList<>();structFieldNames.add("result");structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);return ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, structFieldObjectInspectors);}@Overridepublic Object evaluate(DeferredObject[] deferredObjects) throws HiveException {// 完成两数相加的逻辑计算ArrayList<Integer> arrayList = new ArrayList<>();int num1 = Integer.parseInt(deferredObjects[0].get().toString());int num2 = Integer.parseInt(deferredObjects[1].get().toString());arrayList.add(num1 + num2);return arrayList;}@Overridepublic String getDisplayString(String[] strings) {return getStandardDisplayString("AddTestReturnList", strings);}}

(退出当前与 Hive 的连接,建立新的连接,刷新缓存)

同样的,打包上传到 HDFS 上进行注册:

create function AddTestReturnList as 'AddTestReturnList' using jar 'hdfs://hadoop201:8020/test/MyUDF-1.0-SNAPSHOT-jar-with-dependencies.jar';

此时,可能会发生报错,这是由于我们之前已经加载过该 JAR 包了,再次加载时 Hive 会抛出异常,我们可以通过下面的语句进行调整:

-- 关闭向量化查询
set hive.vectorized.execution.enabled=false;

重新注册即可。

进行测试:

select AddTestReturnList(1,2);

计算结果如下:

在这里插入图片描述

是不是轻松拿捏了~

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

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

相关文章

数组-二维数组

本笔记为47 数组-二维数组定义方式_哔哩哔哩_bilibili的学习笔记 二维数组 定义方式 注&#xff1a; 常用第二种方式定义&#xff0c;原因&#xff1a;第二种方式更清晰列数可以省行数不可省 &#xff0c;详见上述第四种定义方式 示例&#xff1a; 二维数组 数组名 作用&am…

【QT+QGIS跨平台编译】063:【qca-logger+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、qca-logger插件介绍二、QCA下载三、文件分析四、pro文件五、编译实践5.1 windows下编译5.2 linux下编译5.3 macos下编译一、qca-logger插件介绍 QCA::Logger 是 Qt Cryptographic Architecture (QCA) 库中的一个类,它提供了一个简单而灵活的日志…

PostgrerSQL基本使用与数据备份

前言 上篇了解了 PostgrerSQL 数据库的部署PostgreSQL关系型数据库介绍与部署-CSDN博客&#xff0c;本篇将继续就其基本操作、备份与还原内容做相关介绍。 目录 一、数据库的操作 1. 本机登录 2. 开启远程登录 2.1 开放远程端口 2.2 编辑配置文件 2.3 修改配置密码 2.…

xss.pwnfunction-Ma Spaghet!

根据代码得知 这个是根据get传参的并且是由someboby来接收参数的 所以 <script>alert(1137)</script> js并没有执行因为 HTML5中指定不执行由innerHTML插入的<script>标签 所以 ?somebody<img%20src1%20onerror"alert(1337)"> 这样就成…

PowerJob 分布式任务调度简介

目录 适用场景 设计目标 PowerJob 功能全景 任务调度 工作流 分布式计算 动态容器 什么是动态容器? 使用场景 可维护性和灵活性的完美结合 实时日志&在线运维 PowerJob 系统组件 PowerJob 应用场景 PowerJob 的优势 PowerJob&#xff08;原OhMyScheduler&…

Pytorch数据结构:GPU加速

文章目录 一、GPU加速1. 检查GPU可用性&#xff1a;2. GPU不可用需要具体查看问题3. 指定设备4.将张量和模型转移到GPU5.执行计算&#xff1a;6.将结果转移回CPU 二、转移原理1. 数据和模型的存储2. 数据传输3. 计算执行4. 设备管理5.小结 三、to方法的参数类型 一、GPU加速 .…

瑞_Redis_商户查询缓存_添加Redis缓存缓存更新策略

文章目录 项目介绍1 短信登录2 商户查询缓存2.1 什么是缓存2.1.1 缓存的应用场景2.1.2 为什么要使用缓存2.1.3 Web应用中缓存的作用2.1.4 Web应用中缓存的成本 2.2 添加Redis缓存2.2.1 背景2.2.2 缓存模型和思路2.2.3 代码实现2.2.4 测试附&#xff1a;IDEA控制台输出自动换行设…

【动态规划】【01背包】Leetcode 416. 分割等和子集

【动态规划】【01背包】Leetcode 416. 分割等和子集 ---------------&#x1f388;&#x1f388;416. 分割等和子集 题目链接&#x1f388;&#x1f388;------------------- 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0…

竞赛 交通目标检测-行人车辆检测流量计数 - 竞赛

文章目录 0 前言1\. 目标检测概况1.1 什么是目标检测&#xff1f;1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

Python3 Ubuntu

一、安装中文输入法 1.sudo apt install ibus-sunpinyin 2.点击右上角输入法&#xff0c;然后点击加号&#xff0c;输入yin添加进来&#xff0c;最后选中输入法即可 二、安装截屏软件 1.sudo apt install gnome-screenshot 三、安装opencv-python 1.pip3 install --upgrade…

HTTP协议报文的结构的补充和from表单以及ajax表单

响应 状态码 表示了这次请求对应的响应,是什么样的状态(成功,失败,还是其他的情况.还有及其对应的原因&#xff09; 主要有这些类 成功状态码&#xff1a;其中200最常见&#xff0c;表示成功 重定向状态码&#xff1a;很多时候,页面跳转,就可以通过重定向来实现. 还有的时…

智慧牧场数据 7

1 体征数据采集 需求:获取奶牛记步信息 三轴加速度测量&#xff1a;加速度测量计反应的加速向量与当前的受力方向是相反&#xff0c;单位为g 陀螺仪&#xff0c;是用来测量角速度的&#xff0c;单位为度每秒&#xff08;deg/s&#xff09; 2000deg/s 相当于1秒钟多少转 1.1…

小米汽车su7全色系展示源码

源码简介 小米汽车全色系展示源码&#xff0c;小米汽车su7全色系展示源码 安装教程 纯HTML&#xff0c;直接将压缩包上传网站目录解压即可 首页截图 源码下载 小米汽车su7全色系展示源码-小8源码屋源码简介 小米汽车全色系展示源码&#xff0c;小米汽车su7全色系展示源码 …

如何不编程用 ChatGPT 爬取网站数据?

敢于大胆设想&#xff0c;才能在 AI 时代提出好问题。 需求 很多小伙伴&#xff0c;都需要为研究获取数据。从网上爬取数据&#xff0c;是其中关键一环。以往&#xff0c;这都需要编程来实现。 可最近&#xff0c;一位星友在知识星球提问&#xff1a; 这里涉及到一些个人隐私&a…

Redission--布隆过滤器解决缓存穿透问题

布隆过滤器在缓存穿透问题中的使用 布隆过滤器的核心是一个位数组 布隆过滤器的误判 使用Redission的布隆过滤器步骤 添加 Redission 依赖&#xff1a;首先需要将 Redission 添加到你的 Java 项目中&#xff0c;你可以通过 Maven 来添加 Redission 的依赖。 创建 Redissio…

深度学习相关知识

一.环境配置 1.cuda/cudnn安装&#xff1a; 安装cuda之前首先安装vs&#xff0c;vs版本从低到高安装。 a) 安装cuda&#xff1a;首先查看显卡支持的最高CUDA的版本&#xff0c;以便下载对应的CUDA安装包&#xff1b; cmd命令行&#xff1a;nvidia-smi,显示如下&#xff1a;…

【单片机】CJSH22-CH2O,甲醛传感器,甲醛传感器数据读取处理

原理图 解析程序 逻辑是&#xff1a; 1、初始化串口和定时器10ms中断 2、循环读取一帧数据到rev_CH2O_bufferdata 3、在主函数解析数据rev_CH2O_bufferdata 4、最终的pm2.5数值就是CH2O_value 使用CH2O_value的数据即可。 PPB单位&#xff0c;除以1000就是ppm&#xff0c;再…

ASP.NET Core 模型绑定

&#x1f340;介绍 在C#中&#xff0c;特别是在ASP.NET Core中&#xff0c;模型绑定是一个将HTTP请求中的数据映射到C#对象的过程。它使得开发者能够方便地从请求中提取数据&#xff0c;而无需手动解析请求体、查询字符串、路由数据等。ASP.NET Core提供了多种特性&#xff08…

C语言 | Leetcode C语言题解之第13题罗马数字转整数

题解&#xff1a; 题解&#xff1a; int romanToInt(char* s) {int symbolValues[26];symbolValues[I - A] 1;symbolValues[V - A] 5;symbolValues[X - A] 10;symbolValues[L - A] 50;symbolValues[C - A] 100;symbolValues[D - A] 500;symbolValues[M - A] 1000;int a…

迷茫下是自我提升

长夜漫漫&#xff0c;无心睡眠。心中所想&#xff0c;心中所感&#xff0c;忧愁当前&#xff0c;就执笔而下&#xff0c;写下这篇文章。 回忆过往 回想当初为啥学前端&#xff0c;走前端这条路&#xff0c;学校要求嘛&#xff0c;兴趣爱好嘛&#xff0c;还是为了钱。 时间带着…