Hive自定义函数UserDefineFunction
Hive自定义函数UserDefineFunction
分类:
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项目的配置全部删除
-
注意 --- 方法名必须是
evaluate
实现evaluate方法的时候,需要考虑 返回值 及 参数列表 是什么
返回值 --- 将来使用这个方法处理完字段之后需要返回的结果
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 ;