1 定义
Hive UDF(User Defined Function 用户自定义函数),是在Hive内置的处理函数无法满足用户需求时,由用户自行继承接口实现的单行数据处理函数。
Hive 有两个不同的接口编写 UDF 程序。
1 简单数据类型的 UDF 接口
org.apache.hadoop.hive.ql.exec.UDF
基础 UDF 的函数读取和返回基本类型,即 Hadoop 和 Hive 的基本类型。如 Text、IntWritable、LongWritable、DoubleWritable 等。
2 复杂数据类型的 GenericUDF 接口。
org.apache.hadoop.hive.ql.udf.generic.GenericUDF
GenericUDF 可以处理 Map、List、Set 类型。
2 开发
2.1 依赖引入
2.2 简单类型UDF
如果预期输入输出都是int、string和decimal等简单数据类型,实现起来较为简单,只需继承UDF类,实现一个名为evaluate()的方法即可,具体举例如下:
public class UDFtest extends UDF {
public String evaluate(String str,Integer size) {
if (size > str.length()) return str;
return str.substring(0,size);
}
}
2.3 复杂类型UDF
class ComplexUDFExample extends GenericUDF {
// 0. ObjectInspector,通常以成员变量的形式被创建
ListObjectInspector listOI;
StringObjectInspector elementOI;
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 1. 检查该记录是否传过来正确的参数数量
if (arguments.length != 2) {
throw new UDFArgumentLengthException("arrayContainsExample only takes 2 arguments: List<T>, T");
}
// 2. 检查该条记录是否传过来正确的参数类型
ObjectInspector a = arguments[0];
ObjectInspector b = arguments[1];
if (!(a instanceof ListObjectInspector) || !(b instanceof StringObjectInspector)) {
throw new UDFArgumentException("first argument must be a list / array, second argument must be a string");
}
// 3. 检查通过后,将参数赋值给成员变量ObjectInspector,为了在evaluate()中使用
this.listOI = (ListObjectInspector) a;
this.elementOI = (StringObjectInspector) b;
// 4. 检查数组是否包含字符串,是否为字符串数组
if(!(listOI.getListElementObjectInspector() instanceof StringObjectInspector)) {
throw new UDFArgumentException("first argument must be a list of strings");
}
// 5. 用工厂类生成用于表示返回值的ObjectInspector
return PrimitiveObjectInspectorFactory.javaBooleanObjectInspector;
}
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
// get the list and string from the deferred objects using the object inspectors
List<String> list = (List<String>) this.listOI.getList(arguments[0].get());
String arg = elementOI.getPrimitiveJavaObject(arguments[1].get());
// check for nulls
if (list == null || arg == null) {
return null;
}
// see if our list contains the value we need
for(String s: list) {
if (arg.equals(s)) return new Boolean(true);
}
return new Boolean(false);
}
@Override
public String getDisplayString(String[] arg0) {
return "arrayContainsExample()"; // this should probably be better
}