1.UDF和UDTF简介

UDF是User-Define-Function,一般是指一个输入一个输出,UDTF是UDF变种,可一个输入多个输出。UDAF是用户聚合,可以多行输入,一个输出。需要注意的是这些函数写好之后需要在平台或者脚本里配合sql使用。

1.1开发前注意事项

在编写代码时,UDF有两种具体实现,你可以继承import org.apache.hadoop.hive.ql.exec.UDF;来实现UDF,也可以继承public class top extends GenericUDF,第一个不支持复杂数据类型,比如Map,struct等。如果你想解析这些数据必须继承GenernicUDF实现

2.开发一个UDTF的全部流程

2.1配置pom文件的依赖

hive-exec,hadoop-common两个依赖即可

2.2编写业务代码的逻辑实现

2.2.1先写一个简单的UDF

package hive.udf;//必须要写包名。不然一会儿不好导入

import org.apache.hadoop.hive.ql.exec.UDF;//UDF虽然会被提示弃用了但是正常用就行

public class Twosum extends UDF {
        public int evaluate(int input){
            return input+233;
        }
}
  • 包名必须要写,不然hive里没办法把生成的jar包导进去
  • 实现evalute方法即可,经过简单的处理直接return。
  • 其实GenericUDF还有init方法用来初始化,该方法只执行一次,还有display方法用来报错。但是这些都可以不去实现。

2.2.2编写复杂的UDTF

该UDTF是TopN问题ETL部分
pom中依赖还是上面那两个
基本逻辑就是有个很长的字符串,里面是多个key:value的键值对,每一个键值对的分隔符是ETX(EndOfText)也就是ASCII的第三个控制字符(\u0003就是十六进制的3)。每个key和value分隔符是EOT(End Of Transmision)是第四个控制字符。
拆分的结果是每个键值对都被拆成key和value两列。

public class top extends GenericUDTF {
    public static final Logger LOGGER = LogManager.getLogger(top.class);

    @Override
    public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException {
        //定义输出数据的列名
        List<String> filedNames = new ArrayList<String>();
        List<ObjectInspector> fieldOIS = new ArrayList<ObjectInspector>();
        filedNames.add("key");
        fieldOIS.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        filedNames.add("value");
        //定义输出数据的类型
        fieldOIS.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        return ObjectInspectorFactory.getStandardStructObjectInspector(filedNames, fieldOIS);
    }

    @Override
    public void process(Object[] objects) throws HiveException {
        String input = objects[0].toString();
        String[] datadsplit = input.split("\u0003");
        for (String s : datadsplit) {
            String[] result = s.split("\u0004");
            forward(result);
        }
    }

    @Override
    public void close() throws HiveException {

    }

}
  • init方法必须实现,并且得用新的init方法,如果参数输成了老款或者没有实现init方法会报错IllegalStateException Should not be called directly
  • init方法中是用来定义输出信息的,需要注意的是filename add一次filedOIS也得add一次,如果输出多列数据的话。
  • 如果处理完是数列或者数组,直接给forward函数即可。他会返回一行。

2.3配置工件及部署和使用

  • 首先在IDEA左上角项目设置里找到工件,新建一个工件。选依赖辅助项目。然后再工具栏构建中找到构建工件。构建成功后再项目文件的out目录可以看见jar包
  • 上传到hive的服务器,随便一个文件夹就可以,然后cd到该目录
  • zip -d jar包 ‘META-INF/.SF’ ‘META-INF/.RSA’ ‘META-INF/*SF’
  • 使用上述命令消除异常签名
  • 再hive客户端或者datagrip上执行 add jar xxx.jar
  • 继续create function twosum as ‘hive.udf.Twosum’;//这个as后面是包名+类名
  • 接下来就可以调用了
  • select twosum(name) from t_user;

3.TopN问题解法

UDAF函数 hive hive udf udaf udtf_hadoop


上面的函数已经把所有的key:value拆分完毕,接下来做聚合和排序即可

create table topnend as
select types,sum(statusvalue) as value
from topnfinal
group by types;

select * from topnend
order by value desc ;