Hive自定义函数UserDefineFunction

Hive自定义函数UserDefineFunction

自定义函数只针对当前的 hive shell 有效,一旦退出当前shell,则需要重新注册

分类:

UDF:一进一出

UDTF:一进多出

UDAF:多进一出(一般用不到)

UDF:一进一出
  • 创建maven项目,并加入依赖

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

导入依赖的时候可能会出现一个错误 -- pentaho-aggdesigner-algorithm-5.1.5-jhyde.jar包找不到

然后就会跳转到阿里云的仓库(因为之前我们换的就是阿里云的源)

我们可以看到这个包是在spring-plugin这个仓库中的,而我们之前换源的时候选的是central这个仓库。

下载这两个文件

文件下载完之后

找到本地仓库中的这个位置E:\repository\org\pentaho\pentaho-aggdesigner-algorithm\5.1.5-jhyde

将之前下载的两个文件拖到里面

然后刷新一下IDEA的Maven即可

如果不可以的话,试一下下面这几步

刷新IDEAMaven项目、IDEA清除缓存并重启、查看Maven自动忽略的文件、将IDEA该Maven项目的配置全部删除

  • 编写代码,继承org.apache.hadoop.hive.ql.exec.UDF,实现evaluate方法,在evaluate方法中实现自己的逻辑

    注意 --- 方法名必须是 evaluate

    实现evaluate方法的时候,需要考虑 返回值 及 参数列表 是什么

    参数列表 -- 将来在hive中调用方法时传入的字段

    返回值 --- 将来使用这个方法处理完字段之后需要返回的结果

import org.apache.hadoop.hive.ql.exec.UDF;
​
public class HiveUDF extends UDF {
    // hadoop => #hadoop$
    public String evaluate(String col1) {
    // 给传进来的数据 左边加上 # 号 右边加上 $
        String result = "#" + col1 + "$";
        return result;
    }
}
  • 打成jar包并上传至Linux虚拟机

  • 在hive shell中,使用 add jar 路径将jar包作为资源添加到hive环境中

add jar /usr/local/soft/jars/HiveUDF2-1.0.jar;
  • 使用jar包资源注册一个临时函数,fxxx1是你的函数名,'MyUDF'是主类名

create temporary function fxxx1 as 'MyUDF';
  • 使用函数名处理数据

select fxx1(name) as fxx_name from students limit 10;
​
#施笑槐$
#吕金鹏$
#单乐蕊$
#葛德曜$
#宣谷芹$
#边昂雄$
#尚孤风$
#符半双$
#沈德昌$
#羿彦昌$
UDTF:一进多出

"key1:value1,key2:value2,key3:value3"

key1 value1

key2 value2

key3 value3

方法一:使用 explode+split
select split(t.col1,":")[0]
       ,split(t.col1,":")[1] 
from (
     select explode(split("key1:value1,key2:value2,key3:value3",",")) as col1
) t;
方法二:自定UDTF
  • 代码

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;
​
public class HiveUDTF extends GenericUDTF {
    // 指定输出的列名 及 类型
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        ArrayList<String> filedNames = new ArrayList<String>();
        ArrayList<ObjectInspector> filedObj = new ArrayList<ObjectInspector>();
        filedNames.add("col1");
        filedObj.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        filedNames.add("col2");
        filedObj.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        return ObjectInspectorFactory.getStandardStructObjectInspector(filedNames, filedObj);
    }
​
    // 处理逻辑 my_udtf(col1,col2,col3)
    // "key1:value1,key2:value2,key3:value3"
    // my_udtf("key1:value1,key2:value2,key3:value3")
    public void process(Object[] objects) throws HiveException {
        // objects 表示传入的N列
        String col = objects[0].toString();
        // key1:value1  key2:value2  key3:value3
        String[] splits = col.split(",");
        for (String str : splits) {
            String[] cols = str.split(":");
            // 将数据输出
            forward(cols);
        }
​
    }
​
    // 在UDTF结束时调用
    public void close() throws HiveException {
​
    }
}
  • 打成jar包并上传至Linux虚拟机

  • 在hive shell中,使用 add jar 路径将jar包作为资源添加到hive环境中 add jar /usr/local/soft/HiveUDF2-1.0.jar;

  • 使用jar包资源注册一个临时函数 create temporary function my_udtf as 'MyUDTF';

  • 使用函数名处理数据 select my_udtf("key1:value1,key2:value2,key3:value3");

  • 查看Hive的运行日志,日志文件在/tmp/root/hive.log

    通过 tail -f hive.log 命令监听运行日志文件

需求示例

字段:id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12 共13列

数据:

a,1,2,3,4,5,6,7,8,9,10,11,12

b,11,12,13,14,15,16,17,18,19,20,21,22

c,21,22,23,24,25,26,27,28,29,30,31,32

转成3列:id,hours,value

例如:

a,1,2,3,4,5,6,7,8,9,10,11,12

a,0时,1

a,2时,2

a,4时,3

a,6时,4

......

建表语句

create table udtfData(
    id string
    ,col1 string
    ,col2 string
    ,col3 string
    ,col4 string
    ,col5 string
    ,col6 string
    ,col7 string
    ,col8 string
    ,col9 string
    ,col10 string
    ,col11 string
    ,col12 string
)row format delimited fields terminated by ',';

代码:

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;
​
public class HiveUDTF2 extends GenericUDTF {
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        ArrayList<String> filedNames = new ArrayList<String>();
        ArrayList<ObjectInspector> fieldObj = new ArrayList<ObjectInspector>();
        filedNames.add("col1");
        fieldObj.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        filedNames.add("col2");
        fieldObj.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        return ObjectInspectorFactory.getStandardStructObjectInspector(filedNames, fieldObj);
    }
​
    // 传入 col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12
    public void process(Object[] objects) throws HiveException {
        int hours = 0;
        for (Object obj : objects) {
            String col = obj.toString();
            ArrayList<String> cols = new ArrayList<String>();
            cols.add(hours + "时");
            cols.add(col);
            // cols :hours时 col1
            forward(cols);
            hours = hours + 2;
        }
    }
​
    public void close() throws HiveException {
​
    }
}

添加jar资源:

add jar /usr/local/soft/HiveUDF2-1.0.jar;

注册udtf函数:

create temporary function my_udtf as 'MyUDTF';

SQL:

select id from udtfData; --可以

select my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) from udtfData; -- 可以

select id,my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) from udtfData; -- 不可以

因为这样写在Hive中是解析不了的

所以要使用 lateral view

lateral view 用法

select xx from 表 lateral view udtf() 别名1 as 别名2

udtf() -- 不管是内置的也好,还是自定义的,需要一对多的函数

lateral view 后面的udtf() 就好像创建了一个临时的视图一样,需要给这个‘视图’起一个 别名1

as 后面 需要给 前面的函数生成的多列 起 别名2 来接收这些列 ,注 别名2之间用 ' , ' 隔开且不需要加括号

lateral view 原理

就拿下面的代码说明,

1.Lateral View 用于和UDTF函数【explode,split】结合来使用

2.首先通过UDTF函数将数据拆分成多行,再将多行结果组合成一个支持别名的虚拟表。

3.主要解决在select使用UDTF做查询的过程中查询只能包含单个UDTF,不能包含其它字段以及多个UDTF的情况。

4.就像是select id from udtfData 与 my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) 这张虚拟的表做笛卡尔积

select id
       ,hours
       ,value 
from udtfData lateral view my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) t as hours,value ;
UDAF:多进一出

不常用

posted @ 2022-02-23 00:17  赤兔胭脂小吕布  阅读(69)  评论(0编辑  收藏  举报