1介绍
Hive自定义函数包括三种UDF、UDAF、UDTF
UDF(User-Defined-Function) 一进一出
UDAF(User- Defined Aggregation Funcation) 聚集函数,多进一出。Count/max/min
UDTF(User-Defined Table-Generating Functions) 一进多出,如lateral view explore)
使用方式 :在HIVE会话中add 自定义函数的jar文件,然后创建function继而使用函数
1、编写自定义函数
2、打包上传到集群机器中
3、进入hive客户端,添加jar包:hive> add jar /root/hive_udf.jar
4、创建临时函数:hive> create temporary function getLen as 'com.raphael.len.GetLength';
5、销毁临时函数:hive> DROP TEMPORARY FUNCTION getLen;
hive自定义函数中有几类数据类型:
PrimitiveObjectInspector 常用(基本数据类):
PrimitiveObjectInspector.PrimitiveCategory.STRING
ListObjectInspector
StructObjectInspector
MapObjectInspector
等类型
三种自定义函数都会首先进行参数个数和参数类型检查
参数类型检查(是那一种大类型(primitive...),然后具体是什么类型)
注意:在所有方法有返回时要注意返回的类型,最重要的是最后返回出去的结果,一般结果的数据类型会在初始化时就定义了,那么在最后返回结果是应该要转化成那种类型
初始化时init:
PrimitiveObjectInspector inputOI;
inputOI = (PrimitiveObjectInspector) parameters[0];
都会定义这种设置输入数据的 ObjectInspector(类型吧)
有多个参数就会设置多个。
在真正处理数据需要获取数据:
long distinctId = PrimitiveObjectInspectorUtils.getLong(objects[0], distinctIdOI);
一般都这样获取,objects是方法的参数,从外界传递进来的,包含很多值,获取第几个值,同时类型是什么(distinctIdOI)
2 UDF
2.1介绍
hive的udf有两种实现方式或者实现的API,一种是udf比较简单,一种是GenericUDF比较复杂。
如果所操作的数据类型都是基础数据类型,如(Hadoop&Hive 基本writable类型,如Text,IntWritable,LongWriable,DoubleWritable等等)。那么简单的org.apache.hadoop.hive.ql.exec.UDF就可以做到。
如果所操作的数据类型是内嵌数据结构,如Map,List和Set,那么要采用org.apache.hadoop.hive.ql.udf.generic.GenericUDF
2.2继承UDF实现
需要继承org.apache.hadoop.hive.ql.UDF,或者
org.apache.hadoop.hive.ql.udf.generic.GenericUDF,前者比较简单,只需要实现evaluate函数,evaluate函数支持重载。
UDF代码如下:
import org.apache.hadoop.hive.ql.exec.UDF;
public class GetLength extends UDF{
public int evaluate(String str) {
try{
return str.length();
}catch(Exception e){
return -1;
}
}
}
2.3继承GenericUDF实现
继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF需要实现三个方法:
1)initialize:只调用一次,在任何evaluate()调用之前可以接收到一个可以表示函数输入参数类型的object inspectors数组。initalize用来验证该函数是否接收正确的参数类型和参数个数,最后提供最后结果对应的数据类型。
2)evaluate:真正的逻辑,读取输入数据,处理数据,返回结果。
3)getDisplayString:返回描述该方法的字符串,没有太多作用。
继承GenericUDF实现UDF,完成url解码功能代码如下:
public class UrlDecodeUDF2 extends GenericUDF {
private transient PrimitiveObjectInspector inputOI;
public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
// 检查参数数量
if (objectInspectors.length != 1) {
throw new UDFArgumentException("urlDecode() takes only one argument");
}
// 检查参数类型
if (objectInspectors[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
if (((PrimitiveObjectInspector) objectInspectors[0]).getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {
throw new UDFArgumentTypeException(0, "Only String type argument are accepted, but "
+ objectInspectors[0].getTypeName() + " was pass as parameter 1");