大数据Hive中的UDF:自定义数据处理的利器(上)


文章目录

    • 1. 前言
    • 2. UDF与宏及静态表的对比
    • 3. 深入理解UDF
    • 4. 实现自定义UDF

1. 前言

在大数据技术栈中,Apache Hive 扮演着数据仓库的关键角色,它提供了丰富的数据操作功能,并通过类似于 SQLHiveQL 语言简化了对 Hadoop 数据的处理。然而,内置函数库虽强大,却未必能满足所有特定的业务逻辑需求。此时,用户定义函数(User-Defined FunctionsUDF)的重要性便凸显出来。

Hive UDFUser-Defined Function)是Hive中的一种扩展机制,它允许用户通过编写自定义的Java代码来扩展Hive的功能,实现Hive内置函数无法提供的一些特定数据处理逻辑。

2. UDF与宏及静态表的对比

除了UDF可以自定义输入和输出还有例如静态表,宏定义的方式也可以实现类似的操作,举个例子:在数据中筛选出已达到退休年龄的员工。

UDF 示例

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

public class RetirementStatusUDF extends UDF {
    public Text evaluate(int age) {
        return new Text(age >= 60 ? "已达到退休年龄" : "未达到退休年龄");
    }
}

-- 添加UDF的jar包到Hive
ADD JAR /path/to/udf.jar;

-- 创建临时函数
CREATE TEMPORARY FUNCTION retirement_status AS 'com.example.RetirementStatusUDF';

-- 使用UDF进行查询
SELECT name, age, retirement_status(age) AS status
FROM employee_static;

静态表


CREATE TABLE employee_static (
 
  age INT,
  flag STRING -- 'retired' 或 'active'
);



-- 查询已达到退休年龄的员工
SELECT a.*
FROM employee_data a
JOIN employee_static b
ON a.age = b.age AND b.flag = 'retired';

宏定义

drop temporary macro if exists get_retired;

create temporary macro get_retired(age bigint) 
if (
       age is not null,
       case
              when age >= 60 then '退休'
              when age <= 60 then '未退休'
              else null
       end,
       null
);

使用UDF(用户定义函数)的原因与宏和静态表的功能有所不同,它们各自适用于不同的场景和需求。以下是使用UDF的几个关键原因:

特性/方法UDF(用户定义函数)宏(Macro)静态表(Static Table)
定义允许用户通过编写自定义的Java代码来扩展Hive的功能,实现特定的数据处理逻辑。在Hive中,宏是一种用户定义的快捷方式,用于封装一系列HiveQL语句,以便在查询中重复使用。预先定义和填充的数据集,其结构和内容在创建后通常保持不变。
使用场景适用于执行Hive内置函数不支持的特定数据处理逻辑,如复杂的业务规则或算法。主要用于简化和重用HiveQL查询语句,提高代码的可读性和易维护性。适用于存储已知的、不变的数据集,供多次查询使用,无需每次重新计算。
灵活性高,可以根据需求定制数据处理流程。中等,主要用于简化复杂的查询,但不具备动态处理能力。低,结构和内容一旦定义,通常不发生变化。
性能可优化,Hive执行UDF时会进行优化,性能接近内置函数。取决于宏定义的查询的复杂性,可能提高或降低性能。预先计算,查询时性能较高,适合重复查询相同数据集。
重用性高,一旦创建和注册,可以在不同的Hive会话中重复使用。高,宏可以定义一次并在多个查询中重复使用。中等,表结构和数据不变,适用于重复查询相同数据集的场景。
实时性支持实时数据处理,每次调用UDF时根据输入动态执行计算。不直接支持实时数据处理,主要用于查询语句的封装。不支持实时数据处理,通常是预先计算和存储的。
适应性强,可以快速适应新的数据处理需求。中等,需要修改宏定义以适应新的需求。弱,结构和数据固定,不适合频繁变化的数据需求。
示例应用用于实现如复杂数学计算、自定义字符串处理、数据清洗等。用于封装复杂的查询模板,如多步骤的数据转换过程。用于存储配置数据、参考数据或不需要频繁更新的数据。

选择使用UDF、宏还是静态表应基于具体的业务需求、数据特性和性能考虑。每种方法都有其独特的优势和适用场景。

3. 深入理解UDF

Hive UDF可以分为三种主要类型:UDF、UDAF和UDTF。

  1. UDF (User-Defined Function)
    • 标量函数,用于一对一(one-to-one)的映射,即对单个数据项进行操作并返回单个结果。
    • 例如,字符串处理(upper, substr)、数学计算(sqrt)、日期时间转换等。
  2. UDAF (User-Defined Aggregate Function)
    • 聚合函数,用于多对一(many-to-one)的映射,即对多行数据进行聚合操作并返回单个结果。
    • 例如,自定义的求和(sum)、平均值(avg)、最大值(max)、最小值(min)等。
  3. UDTF (User-Defined Table-Generating Function)
    • 表生成函数,用于一对多(one-to-many)的映射,即对单个数据项进行操作并返回多行结果。
    • 例如,explode函数可以将数组或Map类型的列拆分成多行。
类别简称全称描述示例
UDFUser-Defined Function用于实现一对一的映射,即一个输入对应一个输出。将字符串转换为大写。
UDAFUser-Defined Aggregate Function用于实现一对多的映射,即多个输入对应一个输出。计算某个字段的总和或平均值。
UDTFUser-Defined Table-Generating Function用于实现一对多的行生成,即一个输入可以产生多行输出。将数组或映射类型的字段展开成多行数据。

这些UDF类型允许开发者根据特定的数据处理需求,编写和实现自定义的函数逻辑,从而扩展Hive的数据处理能力。通过使用UDF、UDAF和UDTF,用户可以在Hive中实现更加复杂和定制化的数据处理任务。

实现一个UDF通常涉及以下步骤:

  1. 编写UDF类:在Java中创建一个类,实现Hive UDF接口的相应方法。对于标量UDF,这通常是evaluate方法。
  2. 编译与打包:将UDF类编译成Java字节码,并打包成JAR文件。
  3. 上传JAR包:将JAR文件上传到HDFS或其他Hive可以访问的文件系统中。
  4. 注册UDF:在Hive会话中使用ADD JARCREATE TEMPORARY FUNCTION命令注册UDF。
  5. 使用UDF:在Hive查询中调用注册的UDF,就像调用内置函数一样。

4. 实现自定义UDF

在深入探讨Hive UDF的实现之前,让我们首先确保开发环境的准备妥当。对于UDF的编写,推荐使用Maven来配置Java项目,这样可以方便地管理依赖和构建过程。以下是配置Java开发环境的一个示例,包括使用的版本信息和Maven设置:

Apache Maven 3.9.6
Java version: 1.8.0_211,


<?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.example</groupId>
    <artifactId>project202401</artifactId>
    <version>1.0-SNAPSHOT</version>


    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <hadoop.version>3.1.1.7.1.7.2000-305</hadoop.version>
        <hive.version>3.1.3000.7.1.7.2000-305</hive.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>${hive.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>${hadoop.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>central</id>
            <name>Maven Central</name>
            <url>https://repo1.maven.org/maven2/</url>
        </repository>

        <repository>
            <id>cloudera</id>
            <name>Cloudera Repository</name>
            <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
        </repository>
    </repositories>

</project>

下面是一个Hive UDF(用户定义函数)的示例,该UDF的作用是将传入的字符串转换为大写形式。我将对代码进行注释,并解释其工作流程:


import org.apache.hadoop.io.Text;  // 引入Hadoop的Text类,用于处理字符串
import org.apache.hadoop.hive.ql.exec.UDF;  // 引入Hive的UDF类

@SuppressWarnings({"deprecation", "unused"})  // 忽略警告,例如未使用的警告或过时API的警告
public class UpperCaseUDF extends UDF {  // 定义一个名为UpperCaseUDF的类,继承自UDF

    /**
     * 该方法重写了UDF类中的evaluate方法,是UDF的核心。
     * 它接收一个Text类型的数据,然后返回转换为大写的Text类型数据。
     *
     * @param line Text类型的输入数据
     * @return 转换为大写的Text类型的数据
     */
    public Text evaluate(final Text line) {
        // 检查传入的Text是否为非空且内容不为空字符串
        if (null != line && !line.toString().equals("")) {
            // 将Text转换为String,并使用String的toUpperCase方法转换为大写
            String str = line.toString().toUpperCase();
            // 将大写字符串重新设置回Text对象,并返回
            line.set(str);
            return line;
        } else {
            // 如果传入的Text为null或空字符串,则返回一个新的空Text对象
            return new Text();
        }
    }
}

在Hive的较新版本中,推荐使用GenericUDF而不是直接继承UDF。以下是使用GenericUDF实现的UpperCaseUDF2的示例代码,以及对代码的详细解释和工作流程分析:


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.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.hive.ql.udf.UDFType;

@UDFType(deterministic = true, stateful = false) // 标注UDF的特性,确定性且无状态
public class UpperCaseUDF2 extends GenericUDF { // 继承自GenericUDF

    private StringObjectInspector inputOI; // 输入对象检查员,用于检查输入类型
    private StringObjectInspector outputOI; // 输出对象检查员,用于定义输出类型

    /**
     * initialize方法在UDF首次执行时被调用,用于初始化UDF。
     * @param arguments 传入的参数对象检查员数组
     * @return 输出对象检查员
     * @throws UDFArgumentException 如果输入参数不符合预期,抛出异常
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        // 确保传入的参数是字符串类型
        if (arguments == null || arguments.length == 0) {
            throw new UDFArgumentException("arguments array is null or empty.");
        }
        if (!(arguments[0] instanceof StringObjectInspector)) {
            // 如果不是字符串类型,抛出Hive异常
            throw new UDFArgumentException("The input to UpperCaseUDF2 must be a string");
        }
        // 将输入参数的对象检查员赋值给局部变量
        inputOI = (StringObjectInspector) arguments[0];
        // 定义输出对象检查员为可写的字符串对象检查员
        outputOI = PrimitiveObjectInspectorFactory.writableStringObjectInspector;
        // 返回输出对象检查员
        return outputOI;
    }

    /**
     * evaluate方法定义了UDF的实际逻辑,即如何将输入转换为输出。
     * @param arguments 包含延迟计算的输入对象的数组
     * @return 转换后的大写文本
     * @throws HiveException 如果在执行过程中遇到Hive异常
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        // 从延迟对象中获取输入字符串
        Text line = (Text) arguments[0].get();
        // 如果输入不为空,则转换为大写
        if (line != null && !line.toString().isEmpty()) {
            return new Text(line.toString().toUpperCase());
        }
        // 如果输入为空,返回空字符串
        return new Text();
    }

    /**
     * getDisplayString方法返回UDF的可读字符串表示,用于Hive日志和解释计划。
     * @param strings 输入参数的字符串表示,通常由Hive自动生成
     * @return UDF的可读字符串表示
     */
    @Override
    public String getDisplayString(String[] strings) {
        // 返回UDF的名称,用于解释计划和日志
        return "UpperCaseUDF2()";
    }
}
add jar URL/project202401-1.0-SNAPSHOT.jar;
create temporary function UpperCaseUDF as 'com.xx.hive.udf.UpperCaseUDF';
select UpperCaseUDF('Hive Is Fun') a ;

HIVE IS FUN

通过以上步骤,我们能够创建出高效、可靠的Hive UDF,以满足特定的数据处理需求。UDF的开发不仅需要关注功能的实现,还要重视性能优化和代码的可维护性。正确地使用UDF可以显著提升数据处理的效率,为用户提供强大的数据操作能力。

因为篇幅有限,后面两种自定义UDF,会在下一篇博文展开叙述。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

汇编语言(详解)

汇编语言安装指南 第一步&#xff1a;在github上下载汇编语言的安装包 网址&#xff1a;GitHub - HaiPenglai/bilibili_assembly: B站-汇编语言-pdf、代码、环境等资料B站-汇编语言-pdf、代码、环境等资料. Contribute to HaiPenglai/bilibili_assembly development by creat…

STM32 | USART实战案例

STM32 | 通用同步/异步串行接收/发送器USART带蓝牙(第六天)随着扩展的内容越来越多,很多小伙伴已经忘记了之前的学习内容,然后后面这些都很难理解。STM32合集已在专栏创建,方面大家学习。1、通过电脑串口助手发送数据,控制开发板LED灯 从题目中可以挖掘出,本次使用led、延…

【JVM常见问题总结】

文章目录 jvm介绍jvm内存模型jvm内存分配参数jvm堆中存储对象&#xff1a;对象在堆中创建分配内存过程 jvm 堆垃圾收集器垃圾回收算法标记阶段引用计数算法可达性分析算法 清除阶段标记清除算法复制算法标记压缩算法 实际jvm参数实战jvm调优jvm常用命令常用工具 jvm介绍 Java虚…

C++设计模式:适配器模式(十四)

1、定义与动机 定义&#xff1a;将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作。 动机&#xff1a; 在软件系统中&#xff0c;由于应用环境的变化&#xff0c;常常需要将“一些现存的对象”放在新的环境…

【Hadoop】- YARN概述[6]

目录 一、YARN & Reduce 二、分布式资源调度 - YARN 1、资源调度 2、YARN的资源调度 总结 一、YARN & Reduce MapReduce是基于YARN运行的&#xff0c;即没有YARN “无法” 运行MapReduce程序。 二、分布式资源调度 - YARN YARN&#xff08;Yet Another Resou…

注意力机制中多层的作用

1.多层的作用 在注意力机制中&#xff0c;多层的作用通常指的是将注意力机制堆叠在多个层上&#xff0c;这在深度学习模型中被称为“深度”或“多层”注意力网络。这种多层结构的作用和实现过程如下&#xff1a; 1. **逐层抽象**&#xff1a;每一层都可以捕捉到输入数据的不同…

Oracle之SQL plus的一些经验心得

每次登入SQL plus后,不知道时哪个用户登入,非常不方便,只能使用show user查看。 以下时可以通过一些设置实现上述的效果,知道时哪个用户登入,和实现输出效果等 1)SQL plus使用细则 SQL plus登录时,我们可以设置一些通用的设置,在每次登入SQL plus的时候生效。 [root@c…

Eclipse+Java+Swing实现学生信息管理系统-TXT存储信息

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;Eclipse2021 JDK版本&#xff1a;jdk1.8 存储方式&#xff1a;Txt文件存储 2.技术选型 JavaSwingTxt 3.功能模块 4.工程结构 5.系统功能 1.系统登录 管理员可以登录系统。 2.教师-查看学生…

rmallox勒索病毒威胁网络安全:如何避免数据被锁定

尊敬的读者&#xff1a; 随着信息技术的飞速发展&#xff0c;网络空间的安全问题日益凸显。近年来&#xff0c;一种名为.rmallox的勒索病毒频繁出没&#xff0c;给广大计算机用户带来了严重的困扰。本文将对该病毒进行深入剖析&#xff0c;并探讨相应的应对策略。在面对被勒索…

VulnHub靶机 DC-7 打靶 渗透详细流程

VulnHub靶机 DC-7 实战打靶 详细渗透测试流程 目录 VulnHub靶机 DC-7 实战打靶 详细渗透测试流程一、将靶机配置文件导入虚拟机当中二、渗透测试流程主机发现端口扫描目录爆破web渗透白盒测试ssh远程连接 提权修改后台密码GETSHELL反弹shell 一、将靶机配置文件导入虚拟机当中 …

深度神经网络(DNN)

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个深度神经网络&#xff08;DNN&#xff09;模型程序,最后打印5个条件分别的影响力。 示例 在深度神经网络&#xf…

【免费源码下载】完美运营版商城 虚拟商品全功能商城 全能商城小程序 智慧商城系统 全品类百货商城php+uniapp

简介 完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城 干干净净 没有一丝多余收据 还没过手其他站 还没乱七八走的广告和后门 后台可以自由拖曳修改前端UI页面 还支持虚拟商品自动发货等功能 挺不错的一套源码 前端UNIAPP 后端PHP 一键部署版本&am…

51、图论-岛屿数量

思路&#xff1a; 该问题要求在一个由 1&#xff08;表示陆地&#xff09;和 0&#xff08;表示水&#xff09;组成的二维网格中&#xff0c;计算岛屿的数量。岛屿被水包围&#xff0c;并且通过水平或垂直连接相邻的陆地可以形成。这个问题的核心是识别并计数网格中相连的陆地…

ssm068海鲜自助餐厅系统+vue

海鲜自助餐厅系统的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管…

车载电子电器架构 —— 功能安全开发(首篇)

车载电子电器架构 —— 功能安全开发 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己…

go | defer、panic、recover

刷一道题&#xff0c; 将当函数触发panic 之后&#xff0c;函数是怎么执行的 然后我去找相关博客&#xff0c;发现这篇讲的蛮好的 接下来我直接上demo &#xff0c;然后通过demo 来逐个分析 package mainimport ("fmt" )func f() {defer func() {if r : recover();…

断言(Assertion)在IT技术中的确切含义— 基于四类典型场景的分析

当“断言”&#xff08;Assertion&#xff09;一词成为IT术语时&#xff0c;语义的混沌性和二义性也随之而生。那么&#xff0c;何为断言&#xff1f;断言何为&#xff1f;实际上&#xff0c;只需分析四种典型场景&#xff0c;确切答案和准确描述就将自然显现。 在SAML&#xf…

浏览器主页被“绑架”了?按照这个可以修改。

前言 小白是一个很喜欢看新闻的人&#xff0c;浏览器的默认主页通常都是MSN和百度的新闻&#xff0c;这可以说是习惯吧。 电脑用得好好的&#xff0c;有一天浏览器的主页被“绑架”了&#xff0c;变成了“hao***”。我知道&#xff0c;新一轮的检查又准备开始了。 上一次是Wi…

Docker - WEB应用实例

原文地址&#xff0c;使用效果更佳&#xff01; Docker - WEB应用实例 | CoderMast编程桅杆Docker - WEB应用实例 在之前的章节中&#xff0c;仅对普通容器进行了演示&#xff0c;但在实际中常常使用到 Docker 容器中的 WEB 应用程序。 运行一个WEB应用 拉取镜像 创建一个容器…

小型架构实验模拟

一 实验需求 二 实验环境 22 机器&#xff1a; 做nginx 反向代理 做静态资源服务器 装 nginx keepalived filebeat 44机器&#xff1a; 做22 机器的备胎 装nginx keepalived 99机器&#xff1a;做mysql的主 装mysqld 装node 装filebeat 77机器&#xff1a;做mysq…