hive编写自定函数udf、udtf

编写hive自定义函数的时候,查阅很多文档都没有写清楚,现将代码过程进行编写,方便后续复习

1、内置函数

hive本身会自带一些内置函数,由于数量有限,需要编写自定义函数来方便公司的业务扩展。

2、用户自定义函数类别

UDF(User-Defined-Function) 一进一出

UDAF(User-Defined Aggregation Function) 聚合函数,多进一出,如:count/max/min

UDTF(User-Defined Table-Generating Functions) 炸裂函数,一进多出,如:explode()

 3、官网文档

HivePlugins - Apache Hive - Apache Software Foundation

4、编程实现步骤

导入pom.xml文件。这是我的项目,仅供参考

<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>com.gyyx</groupId>
  <artifactId>get_grid_line</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>Maven</name>
  <url>http://maven.apache.org/</url>
  <inceptionYear>2001</inceptionYear>

  <distributionManagement>
    <site>
      <id>website</id>
      <url>scp://webhost.company.com/www/website</url>
    </site>
  </distributionManagement>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>


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

 
  </dependencies>

</project>

编写udf函数代码

需要继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF包,实现类中的抽象方法

package gyyx.utils;

import org.apache.hadoop.hive.ql.exec.Description;
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;

/**
 * @author niehandong
 * @since 1.0.0
 */
@Description(name = "get_grid_line", value = "Returns a formatted string from multiple input strings")
public class GridLines extends GenericUDF {

    /*
         这个方法主要是对自定义的UDF函数进行初始化,目的是指定调用完函数返回的值的类型
         需求:传入多个字符串,返回一个新的字符串
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        // 确保至少有3个参数
        if (arguments.length != 3) {
            throw new UDFArgumentException("get_grid_line requires exactly 3 arguments.");
        }
        // 使用PrimitiveObjectInspectorFactory工厂类,获取String类型的ObjectInspector
        for (ObjectInspector oi : arguments) {
            if (!oi.getCategory().equals(ObjectInspector.Category.PRIMITIVE) ||
                    !((PrimitiveObjectInspector) oi).getPrimitiveCategory().equals(PrimitiveObjectInspector.PrimitiveCategory.STRING)) {
                throw new UDFArgumentException("All arguments must be strings.");
            }
        }
        return PrimitiveObjectInspectorFactory.javaStringObjectInspector; // 返回类型为String
    }

    /*
        该方法是自定义UDF的核心方法,目的是实现自定义UDF的逻辑
        arguments将来会有多个参数
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        String longitude = arguments[0].get().toString();
        String latitude = arguments[1].get().toString();
        String type = arguments[2].get().toString();

        return longitude+latitude+type+"随机数";
    }

    @Override
    public String getDisplayString(String[] children) {
        return "这是我们自己使用新版本写法自定义的UDF函数,接收多个字符串并返回拼接结果";
    }

}

测试数据:

首先在hive命令行创建函数。我采用的是将jar上传到hdfs上,通过hdfs注册。期间试过通过本地路径上传。没有成功,报错显示只能通过hdfs路径上传

#方法一
#TEMPORARY  为临时函数,关闭连接后就失效了
CREATE TEMPORARY FUNCTION get_grid_line as 'gyyx.utils.GridLines' using jar 'hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar';



#方法二:
# 添加jar包路径
ADD JAR hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar;

#创建函数,注意这个不是临时函数,需要将TEMPORARY  加上才是临时函数
CREATE FUNCTION get_grid_line as 'gyyx.utils.GridLines';
hive> select get_grid_line('116.301768','40.055783','rr');
OK
116.30176840.055783rr随机数
Time taken: 2.572 seconds, Fetched: 1 row(s)

编写udtf函数

package gyyx.utils;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
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.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * @author niehandong
 * @since 1.0.0
 */
public class GridLinesUDTF extends GenericUDTF {

    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //创建一个List集合存储结果列的名字
        List<String> colNames = new ArrayList<>();
        //创建一个集合存储每一列的数据类型
        List<ObjectInspector> colTypes = new ArrayList<>();

        //向集合中添加元素,设置列的名字以及类型
        colNames.add("id");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        colNames.add("name");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        colNames.add("cardId");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        //返回一个对象,该对象封装了列的名字以及列的类型
        return ObjectInspectorFactory.getStandardStructObjectInspector(colNames, colTypes);
    }

    @Override
    public void process(Object[] args) throws HiveException {

        //创建一个数组,存储每一列的数据
        //因为结果一行数据中有3列,需要创建一个长度为3的数组,用来存储我们处理过的一行三列数据
        String[] rows = new String[3];

        //args[0]是传入的第一个列数据
        String col = args[0].toString();
        String[] infos = col.split(",");
        //遍历切分后的数组,得到每一个用户信息
        for (String info : infos) {
            String[] strings = info.split("#");
            for (String i : strings) {
                if(i.startsWith("M")){ // M1001
                    rows[0] = i.substring(1);
                }else if(i.startsWith("S")){
                    rows[2] = i.substring(1);
                }else {
                    rows[1] = i;
                }
            }
            //forward(Object o) 调用概述方法,将输出的一行数据,封装成一个数组,传入到forward方法中,给hive后续处理
            forward(rows);
        }
    }

    @Override
    public void close() throws HiveException {

    }
}

测试数据:

#方法一
#TEMPORARY  为临时函数,关闭连接后就失效了
CREATE TEMPORARY  FUNCTION get_grid_lineudf as 'gyyx.utils.GridLinesUDTF' using jar 'hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar';



#方法二:
# 添加jar包路径
ADD JAR hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar;

#创建函数,注意这个不是临时函数,需要将TEMPORARY  加上才是临时函数
CREATE FUNCTION get_grid_lineudf as 'gyyx.utils.GridLinesUDTF';
hive> select get_grid_lineudf('M1001#xiaohu#S324231212,lkd#M1002#S2543412432,S21312312412#M1003#bfy');
OK
1001	xiaohu	324231212
1002	lkd	2543412432
1003	bfy	21312312412
Time taken: 0.175 seconds, Fetched: 3 row(s)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值