Hive自定义函数UDF、UDTF

Hive自定义函数UDF、UDTF

  • hive中已经自带一些函数,但数量有限,有时候需要自己定义函数,自定义函数分为一下三种:

    • 1、UDF(User-Defined-Function)
      一进一出
      类似于:lower/upper/reverse
    • 2、UDAF(User-Defined Aggregation Function)
      聚集函数,多进一出
      类似于:count/max/min
      3、UDTF(User-Defined Table-Generating Functions)
      一进多出
      如lateral view explode()

1.自定义UDF

  • 需求字符串大小写转换

1.1依赖

<dependencies>
    <dependency>
        <groupId>org.apache.hive</groupId>
        <artifactId>hive-exec</artifactId>
        <version>2.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.7.5</version>
    </dependency>
</dependencies>

1.2代码实现


/**
 * @ClassName Uppercase
 * @Description //转大写测试
 * 用于 Hive 的用户定义函数 (UDF)。
 * 新的 UDF 类需要从这个 UDF 类继承(或从GenericUDF继承,它以更高的复杂性为代价提供了更多的灵活性)。
 * 扩展此 UDF 的所有类的要求是:
 * 实现一个或多个名为evaluate方法,这些方法将由 Hive 调用(可以通过设置自定义UDFMethodResolver来配置 Hive 解析要调用的方法的确切方式)。 以下是一些示例:
 * public int evaluate();
 * public int evaluate(int a);
 * public double evaluate(int a, double b);
 * public String evaluate(String a, int b, Text c);
 * public Text evaluate(String a);
 * public String evaluate(List<Integer> a); (请注意,Hive 数组在 Hive 中表示为Lists 。因此ARRAY<int>列将作为List<Integer>传入。)
 * evaluate永远不应该是一个无效的方法。 但是,如果需要,它可以返回null 。
 * 返回类型和方法参数可以是 Java 原语或相应的Writable类。
 * 这个类的一个实例将被每个 JVM 实例化,并且不会被并发调用。
 * @Author mengfd
 * @Date 2021/11/22 15:27
 **/
public class Uppercase extends UDF {

    public Text evaluate(final Text s) {
        if (null == s) {
            return null;
        }
        //返回大写字母
        return new Text(s.toString().toUpperCase());
    }

}

1.3 函数使用

1.3.1 临时函数
  • 向hive的客户端添加jar包
cd /export/server/hive-2.1.0/lib
mv user-defined-function-1.0-SNAPSHOT.jar my_uppercase.jar
  • 连接hive,添加自定义临时函数
add jar /export/server/hive-2.1.0/lib/my_uppercase.jar;
-- 自定义临时函数
create temporary function my_upercase as 'com.dk.udf.Uppercase';
-- 使用函数
select my_upercase("abcDe");
1.3.2 永久函数
  • 上传jar到HDFS中
# 在hdfd创建jar包存放的文件夹
hadoop fs -mkdir /hive_func
# 上传jar包
hadoop fs -put /export/server/hive-2.1.0/lib/my_uppercase.jar /hive_func
  • 连接hive,添加自定义函数
# 创建永久函数
create function my_upercase2 as 'com.dk.udf.Uppercase'
    using jar 'hdfs://node1:8020/hive_func/my_uppercase.jar';
# 使用
select my_upercase2("abcDe");

2. 自定义UDTF

  • 需求字符串一进多出

2.1 单列一进多出转换

2.1.1 代码实现

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;

/**
 * @ClassName SplitString
 * @Description UDTF 单列一进多出,
 *  字符串拆分
 *      参数1:需要拆分的数据
 *      参数2:分隔符
 * @Author mengfd
 * @Date 2021/11/22 16:57
 **/
public class SplitString extends GenericUDTF {


    /** 初始化输出的字段 */
    private final transient Object[] forwardList = new Object[1];

    /**
     * 初始化字段和检查器方法
     * @param argOIs
     * @return
     * @throws UDFArgumentException
     */
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //初始化字段列表
        List<String> fieldNames = new ArrayList<>();
        fieldNames.add("column_1");
        //初始化字段检查器列表,用于检查字段类型
        List<ObjectInspector> inspectors = new ArrayList<>();
        //设置第一个字段类型为string
        inspectors.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, inspectors);
    }


    @Override
    public void process(Object[] args) throws HiveException {
        if (args == null || args.length < 1){
            super.forward(forwardList);
            return;
        }
        //获取需要拆分的数据
        String argsStr = args[0].toString();
        //获取字段分隔符
        String splitStr = args[1].toString();
        //获取拆分后的数组
        String[] fields = argsStr.split(splitStr);
        for (String field : fields) {
            //放入输出字段集合
            forwardList[0] = field;
            //输出
            super.forward(forwardList);
        }
    }

    @Override
    public void close() throws HiveException {

    }
}
2.1.2 函数使用
add jar /export/server/hive-2.1.0/lib/my_split_string.jar;
create temporary function split_string_udtf as 'com.dk.udtf.SplitString';

select split_string_udtf("索隆,路飞,山治,乔巴", ",");

2.2 多列一进多出转换

2.2.1 代码实现

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.Arrays;
import java.util.List;

/**
 * @ClassName SplitMapList
 * @Description UDTF一进多出,多列
 *  入参:
 *      参数1:需要拆分的数据,“路飞:12000000000,索隆:8000000000,乔巴:3000000”
 * @Author mengfd
 * @Date 2021/11/22 18:39
 **/
public class SplitMapList<main> extends GenericUDTF {

    /**初始化一个长度为2的输出列表*/
    private final transient Object[] fieldlist = new Object[2];

    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //初始化列名
        List<String> fieldList = new ArrayList<>();
        fieldList.add("column_1");
        fieldList.add("column_2");
        //初始化字段检查器,分别对应上面两个输出列的类型
        List<ObjectInspector> inspectors = new ArrayList<>();
        inspectors.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        inspectors.add(PrimitiveObjectInspectorFactory.javaLongObjectInspector);
        //返回列名和字段检查器集合
        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldList, inspectors);
    }

    @Override
    public void process(Object[] args) throws HiveException {
        if (args == null || args.length < 1){
            super.forward(fieldlist);
            return;
        }
        //arg0需要分析的数据
        String arg0 = args[0].toString();
        //arg1第一个分隔符
        String arg1 = args[1].toString();
        //arg2第二个分隔符
        String arg2 = args[2].toString();
        String[] items = arg0.split(arg1);
        for (String item : items) {
            String[] beans = item.split(arg2);
            fieldlist[0] = beans[0];
            fieldlist[1] = Long.parseLong(beans[1]);
//            fieldlist[1] = beans[1];
            super.forward(fieldlist);
        }
    }

    @Override
    public void close() throws HiveException {

    }

    public static void main(String[] args) {
        String[] strings = new String[3];
        strings[0] = "路飞:12000000000,索隆:8000000000,乔巴:3000000";
        strings[1] = ",";
        strings[2] = ":";
        //arg0需要分析的数据
        String arg0 = strings[0].toString();
        //arg1第一个分隔符
        String arg1 = strings[1].toString();
        //arg2第二个分隔符
        String arg2 = strings[2].toString();
        String[] items = arg0.split(arg1);
        for (String item : items) {
            String[] beans = item.split(arg2);
            System.out.println(Arrays.toString(beans));
        }
    }
}

2.2.2 函数使用
-- mv user-defined-function-1.0-SNAPSHOT.jar my_split_map.jar
drop function my_split_map;
create function my_split_map as 'com.dk.udtf.SplitMapList'
    using jar 'hdfs://node1:8020/hive_func/my_split_map.jar';

select my_split_map("路飞:12000000000,索隆:8000000000,乔巴:3000000", ",", ":");

2.3 删除函数命令

-- 删除临时函数 
drop temporary function if exists encryptPhoneNumber; 
-- 删除永久函数,不会删除HDFS上的jar包 
drop function if exists my_lower2;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值