Hive自定义UDF函数

news2025/1/11 7:10:03

以下基于hive 3.1.2版本

Hive中自定义UDF函数,有两种实现方式,一是通过继承org.apache.hadoop.hive.ql.exec.UDF类实现,二是通过继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF类实现。

无论是哪种方式,实现步骤都是:

  1. 继承特定类,实现接口或方法
  2. 打jar包
  3. 将生成的jar包加入到hive环境中
  4. 在hive中创建jar包中实现类的对应函数

首先引入pom依赖:

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

1. UDF实现

继承UDF类实现时只需要实现evaluate方法就可以了,写之前,找了replace函数的源码用来参考,源码贴在下面:

package org.apache.hadoop.hive.ql.udf;

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


/**
 * UDFReplace replaces all substrings that are matched with a replacement substring.
 *
 */
@Description(name = "replace",
    value = "_FUNC_(str, search, rep) - replace all substrings of 'str' that "
    + "match 'search' with 'rep'", extended = "Example:\n"
    + "  > SELECT _FUNC_('Hack and Hue', 'H', 'BL') FROM src LIMIT 1;\n"
    + "  'BLack and BLue'")
public class UDFReplace extends UDF {

  private Text result = new Text();

  public UDFReplace() {
  }

  public Text evaluate(Text s, Text search, Text replacement) {
    if (s == null || search == null || replacement == null) {
      return null;
    }
    String r = s.toString().replace(search.toString(), replacement.toString());
    result.set(r);
    return result;
  }
}

模仿上面,自己定义了个函数,功能和hive中的repeat函数一样:

package com.demo.hive;

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


@Description(name = "my_repeat",				// 用于描述该类在hive中对应的函数名,一般与hive中的映射函数名保持一致
        value = "_FUNC_(str, n): repeat str n times",       // "desc function xxx"时显示的内容
        extended = "Example SQL: select _FUNC_('a',3);\nResult: 'aaa'")   // "desc function extended xxx"时显示的内容
public class MyUDFRepeat extends UDF {
    // 涉及到hive中的字符或字符串类型,建议使用Text类处理
    private Text res = new Text();

    public Text evaluate(Text str, IntWritable n) {
        if (str == null || n == null) {
            return null;
        }

        if (n.get() > 0) {
            byte[] arr = str.getBytes();
            byte[] newArr = new byte[str.getLength() * n.get()];

            for (int i = 0; i < n.get(); i++) {
                System.arraycopy(arr, 0, newArr, i * str.getLength(), str.getLength());
            }
            res.set(newArr);
        }
        return res;
    }
}

在写上面这个函数时,最开始出现了一些问题,逻辑上怎么检查都没看出来,捯饬了将近一天才发现原来是Text类中的getByte()和String中的getByte()略有区别(返回的字节数组长度并不相等),后来将所有的str.getbytes().length换成str.getLength()就好了,这里以后再深入研究一下。关于Text类的API:https://hadoop.apache.org/docs/r3.1.2/api/index.html

将上面源码打成jar包之后上传到hive服务所在主机或者hadoop上,然后在本地idea中执行:

add jar /root/HiveLib/hive_udf-1.0-SNAPSHOT.jar;						// jar包加入到hive环境
create temporary function my_repeat as 'com.demo.hive.MyUDFRepeat';		// 创建临时函数,只对当前session生效

创建完函数可以查看一下函数详细信息:
desc function extended my_repeat;
在这里插入图片描述
跑下测试数据验证效果:
select *,my_repeat(name,2),repeat(name,2) from db_prac.employee;
在这里插入图片描述

2. GenericUDF实现

同样先贴一下length函数的源码,通过GenericUDF类实现需要实现父类中的三个抽象方法:initialize()、evaluate()、getDisplayString()

package org.apache.hadoop.hive.ql.udf.generic;

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.exec.vector.VectorizedExpressions;
import org.apache.hadoop.hive.ql.exec.vector.expressions.StringLength;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.serde2.lazy.LazyBinary;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorConverter;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IntWritable;

/**
 * GenericUDFLength.
 *
 */
@Description(name = "length",
    value = "_FUNC_(str | binary) - Returns the length of str or number of bytes in binary data",
    extended = "Example:\n"
    + "  > SELECT _FUNC_('Facebook') FROM src LIMIT 1;\n" + "  8")
@VectorizedExpressions({StringLength.class})
public class GenericUDFLength extends GenericUDF {
  private final IntWritable result = new IntWritable();
  private transient PrimitiveObjectInspector argumentOI;
  private transient PrimitiveObjectInspectorConverter.StringConverter stringConverter;
  private transient PrimitiveObjectInspectorConverter.BinaryConverter binaryConverter;
  private transient boolean isInputString;

  @Override
  public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
    if (arguments.length != 1) {
      throw new UDFArgumentLengthException(
          "LENGTH requires 1 argument, got " + arguments.length);
    }

    if (arguments[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
      throw new UDFArgumentException(
          "LENGTH only takes primitive types, got " + argumentOI.getTypeName());
    }
    argumentOI = (PrimitiveObjectInspector) arguments[0];

    PrimitiveObjectInspector.PrimitiveCategory inputType = argumentOI.getPrimitiveCategory();
    ObjectInspector outputOI = null;
    switch (inputType) {
      case CHAR:
      case VARCHAR:
      case STRING:
        isInputString = true;
        stringConverter = new PrimitiveObjectInspectorConverter.StringConverter(argumentOI);
        break;

      case BINARY:
        isInputString = false;
        binaryConverter = new PrimitiveObjectInspectorConverter.BinaryConverter(argumentOI,
            PrimitiveObjectInspectorFactory.writableBinaryObjectInspector);
        break;

      default:
        throw new UDFArgumentException(
            " LENGTH() only takes STRING/CHAR/VARCHAR/BINARY types as first argument, got "
            + inputType);
    }

    outputOI = PrimitiveObjectInspectorFactory.writableIntObjectInspector;
    return outputOI;
  }

  @Override
  public Object evaluate(DeferredObject[] arguments) throws HiveException {
    byte[] data = null;
    if (isInputString) {
      String val = null;
      if (arguments[0] != null) {
        val = (String) stringConverter.convert(arguments[0].get());
      }
      if (val == null) {
        return null;
      }

      data = val.getBytes();

      int len = 0;
      for (int i = 0; i < data.length; i++) {
        if (GenericUDFUtils.isUtfStartByte(data[i])) {
          len++;
        }
      }
      result.set(len);
      return result;
    } else {
      BytesWritable val = null;
      if (arguments[0] != null) {
        val = (BytesWritable) binaryConverter.convert(arguments[0].get());
      }
      if (val == null) {
        return null;
      }

      result.set(val.getLength());
      return result;
    }
  }

  @Override
  public String getDisplayString(String[] children) {
    return getStandardDisplayString("length", children);
  }
}

模仿上面,下面写了个判断是否是子字符串的函数:

package com.demo.hive;


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.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;

@Description(name = "str_contains", value = "_FUNC_(str1, str2): return true if str1 contains str2, else return false")
public class MyGenericUDFContains extends GenericUDF {
    private StringObjectInspector pos1;
    private StringObjectInspector pos2;

    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        // 检查参数个数
        if (arguments.length != 2) {
            throw new UDFArgumentLengthException("参数个数必须为2");
        }
        // 检查参数类型
        if (!(arguments[0] instanceof StringObjectInspector) || !(arguments[1] instanceof StringObjectInspector)) {
            throw new UDFArgumentException("参数必须都为String类型");
        }
        this.pos1 = (StringObjectInspector) arguments[0];
        this.pos2 = (StringObjectInspector) arguments[1];
        // 函数结果返回类型为布尔类型
        return PrimitiveObjectInspectorFactory.javaBooleanObjectInspector;
    }

    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        String str1 = this.pos1.getPrimitiveJavaObject(arguments[0].get());
        String str2 = this.pos2.getPrimitiveJavaObject(arguments[1].get());
        return str1.contains(str2) ? Boolean.TRUE : Boolean.FALSE;
    }

    @Override
    public String getDisplayString(String[] children) {
        return getStandardDisplayString("str_contains", children);
    }
}

打jar包上传之后,创建映射函数:
create temporary function str_contains as 'com.demo.hive.MyGenericUDFContains';
查看一下函数信息:
desc function extended str_contains;
在这里插入图片描述
跑一下测试数据:
select name, str_contains(name,"i") from db_prac.employee;
在这里插入图片描述
end

总结

  1. UDF类实现简单,只需要实现evaluate()方法就可以了,并且该方法支持重载;GenericUDF类相对于UDF类复杂了一些,但提供了更加灵活的参数检查和更丰富的参数类型,开发中根据实际情况选择。
  2. 上面的注册方式为临时注册,注册的函数只在当前session有效,一般只是测试使用。如果需要永久注册,可以先将jar包上传hdfs,然后通过命令create function my_repeat as 'com.demo.hive.MyUDFRepeat' using jar "hdfs:/user/hive/lib/hive_udf-1.0-SNAPSHOT.jar";永久注册。
    删除注册过的函数:drop [temporary] function xxx;

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

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

相关文章

网上超市系统

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 研究内容&#xff1a;设计开发简单购网上超市系统&#xff0c;采用Java语言&#xff0c;使用ySQL数据库&#xff0c; 实…

毕业设计 单片机家用燃气可视化实时监控报警仪 - 物联网 嵌入式 stm32

文章目录0 前言1 简介2 主要器件3 实现效果4 设计原理4.1 硬件部分4.2 软件部分5 部分核心代码6 最后0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两…

SAP ABAP 开发管理 代码内存标记 位置使用清单(Mark of memory id)

SAP ABAP 开发管理 代码内存标记 位置使用清单&#xff08;Mark of memory id&#xff09; 引言&#xff1a; 代码内存标记&#xff08;Mark of memory id&#xff09;是我开发中对 ABAP MEMORY ID 使用管理的一种方法&#xff0c;他能有效保障使用了 ABAP MEMORY ID 程序的可…

25岁从运维转向软件开发是选择Python还是Java

25岁的年龄不大&#xff0c;若是有扎实的基础&#xff0c;后期转转向软件开发是个不错的选择&#xff0c;Python是目前最火的编程语言&#xff0c;python作为人工智能的主要编程语言也有着不错的发展前景。 关于编程语言的选择&#xff0c;如果从就业的角度出发应该重点考虑一…

[附源码]Nodejs计算机毕业设计基于框架的校园爱心公益平台的设计与实现Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

Mechatrolink III转EtherCAT网关模块解决方案

概述 工业以太网在工业控制领域越来越流行&#xff0c;协议种类较多&#xff0c;例如Mechatrolink III、EtherCAT、Powerlink、Profinet、EtherNet/IP等等&#xff0c;在数控加工领域主流的协议有Mechatrolink III、EtherCAT。但是各种协议之间很难通信协作。 安川电机的Mech…

CPOFDM-16QAM性能仿真,输出接收端的星座图

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 CP-OFDM&#xff08;Cyclic Prefix Orthogonal Frequency Division Multiplexing&#xff0c;循环前缀正交频分复用&#xff09;通信系统采用多个正交子载波&#xff08;Orthogonalsub-Carrier&a…

非科班出身零基础能学好编程吗

近几年IT行业越来越火热&#xff0c;有很多人想转行跨界进入这个行业&#xff0c;那么作为初学者的你&#xff0c;是不是也很困惑&#xff0c;0基础非科班出身能学好编程吗&#xff1f; 编程是一个技术活&#xff0c;没有专业知识想进入这个行业是行不通的&#xff0c;这也决定…

Go工程化项目布局

如果你尝试学习Go&#xff0c;或者你正在为自己建立一个Poc或者一个玩具项目&#xff0c;这个项目布局是没有啥必要的&#xff0c;从一些简单的事情开始&#xff08;一个main文件绰绰有余&#xff09;。当有更多的人参与这个项目的时候&#xff0c;你讲需要更多的结构&#xff…

基于springboot超市进销存管理系统(Java毕业设计,包含部署文档)

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

神经网络种类及应用领域,常用的神经网络有哪些

1、神经网络算法的三大类分别是&#xff1f; 神经网络算法的三大类分别是&#xff1a; 1、前馈神经网络&#xff1a; 这是实际应用中最常见的神经网络类型。第一层是输入&#xff0c;最后一层是输出。如果有多个隐藏层&#xff0c;我们称之为“深度”神经网络。他们计算出一…

[附源码]Python计算机毕业设计Django网上鲜花购物系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

一篇文章带你轻松手撕AVL树的构建

1.AVL树介绍 我们知道一般情况下二叉搜索树的查找效率是很高的&#xff0c;但是遇到极端情况下时间复杂度就会来到O(N) 那么为了消除这种极端情况的影响&#xff0c;我们就需要调节这个二叉树通过一些操作转成一颗二叉平衡树&#xff0c;调节完毕就会得到一颗AVL树。 2.AVL树模…

【Linux】第二部分 保姆级手把手教你如何安装Linux

【Linux】第二部分 保姆级手把手教你如何安装Linux 文章目录【Linux】第二部分 保姆级手把手教你如何安装Linux2.保姆级手把手教你如何安装Linux首先下载vmware接下来下载centOS**接着开启虚拟机,对操作系统进行配置**总结2.保姆级手把手教你如何安装Linux 首先下载vmware vm…

阿里云服务器安装oracle11g

1.服务器配置 //linux版本 CentOS-7-x86_64 //oracle版本 linux.x64_11gR2 //查看服务器的CPU个数 cat /proc/cpuinfo | grep physical | sort -n | uniq | wc -l //查看服务器的型号 dmidecode -s system-product-name //查看服务器的cpu型号…

LeetCode题解 14 (3,98) 无重复字符的最长子串,验证二叉搜索树

文章目录无重复字符的最长子串(3)代码解答&#xff1a;验证二叉搜索树(98)代码解答&#xff1a;无重复字符的最长子串(3) 从题目中可以得知我们要找到该字符串中没有重复元素的最长字串,这道题可以采用滑动窗口的方法来解决,今天在这里我们采用新的方法来解决。 首先我们先将该…

转行学Python开发 怎么快速入门

对于很多转行的新手而言&#xff0c;直接参加培训班是最省时省力的事情&#xff0c;参加培训班既不用担心自己学不会&#xff0c;也不用担心遇到不懂的问题时没有人解答&#xff0c;更重要的是培训班理论实践的教学更贴合实际市场需求。 Python目前是IT行业需求量最大的语言&a…

能够让你装逼的10个Python小技巧

列表推导式 你有一个list&#xff1a; bag [1, 2, 3, 4, 5] 现在你想让所有元素翻倍&#xff0c;让它看起来是这个样子&#xff1a; [2, 4, 6, 8, 10] 大多初学者&#xff0c;根据之前语言的经验会大概这样来做 bag [1, 2, 3, 4, 5] for i in range(len(bag)): bag[i] ba…

GitHub要求所有用户在2023年底前启用双因素身份验证

©网络研究院 GitHub 将要求所有在平台上贡献代码的用户在 2023 年底之前启用双因素身份验证 (2FA) 作为对其帐户的额外保护措施。 双因素身份验证通过在需要输入一次性代码的登录过程中引入额外步骤来提高帐户的安全性。 对于 GitHub 用户来说&#xff0c;账户接管可能…

猿如意中的【Wireshark】网络包分析工具详情介绍

一、工具名称 Wireshark-win64-3.6.5 二、下载安装渠道 Wireshark-win64-3.6.5 通过CSDN官方开发的【猿如意】客户端进行下载安装。 对&#xff0c;你没有看错&#xff0c;就是来自CSDN官方&#xff0c;这次&#xff0c;CSDN果然没有辜负广大技术人的期望&#xff0c;现在…