前言
前两篇文章针对同一个解析Hive复杂字段的需求分别采用了Hive 自带函数(lateral view ,explode,正则表达式)和简单UDF的方式来实现,在采用简单UDF方式处理的时候发现,UDF函数返回的必须是Hive的基本类型,如Text,IntWritable,DoubleWritable,LongWritable等,具体在此次需求中UDF返回的是字符串,每个HotelId用逗号分隔,在真正使用时,仍需要通过split函数拆分成数组形式。
本篇文章就是在上一篇简单UDF的基础上,通过继承GenericUDF的方式,直接返回array类型的结果
Hive GenericUDF
GenericUDF实现比较复杂,需要先继承GenericUDF。这个API需要操作Object Inspectors,并且要对接收的参数类型和数量进行检查。GenericUDF需要实现以下三个方法:
//这个方法只调用一次,并且在evaluate()方法之前调用,该方法接收的参数是一个ObjectInspectors数组,该方法检查接收正确的参数类型和参数个数
abstract ObjectInspector initialize(ObjectInspector[] arguments);
//这个方法类似evaluate方法,处理真实的参数,返回最终结果
abstract Object evaluate(GenericUDF.DeferredObject[] arguments);
//此方法用于当实现的GenericUDF出错的时候,打印提示信息,提示信息就是该方法的返回的字符串
abstract String getDisplayString(String[] children);
实例
import java.util.ArrayList;
import java.util.Date;
import net.sf.json.JSONObject;
import net.sf.json.JSONArray;
import org.apache.hadoop.hive.ql.exec.MapredContext;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache,hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
//继承GenericUDF
public class GetHotelidSenior extends GenericUDF{
private static int mapTasks=0;
private static String init="";
private transient ArrayList<Integer> ret=new ArrayList<Integer>();//存放返回list
@Override
public void configure(MapredContext context){
System.out.println(new Date()+"###### configure");
if(null!=context){
//从jobconf中获取map数
mapTasks=context.getJobConf().getNumMapTasks();
}
System.out.println(new Date()+"###### mapTasks["+mapTasks+"]..");
}
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException{
System.out.println(new Date()+"##### initialize");
//初始化文件系统,可以在这里初始化读取文件
init="init";
//定义函数的返回类型为Java的list
ObjectInspector returnOi=PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(PrimitiveObjectInspector.PrimitiveCategory.INT);
return ObjectInspectorFactory.getStandardListObjectInspector(returnOi);
}
@Override
public Object evaluate(GenericUDF.DeferredObject[] args) throws HiveException{
ret.clear();
try {
JSONObject jb=JSONObject.fromObject(args[0].get().toString());
JSONArray ja=jb.getJSONArray("htllist");
for (int i = 0; i < ja.size(); i++) {
JSONObject jbi = ja.getJSONObject(i);
if (jbi.has("hotelid")) {
ret.add(jbi.getInt("hotelid"));
}
}
}catch (net.sf.json.JSONException ex){
return null;
}
return ret;
}
@Override
public String getDisplayString(String[] str){
return "Usage:GetHotelIdSenior(String str)";
}
}
小结
这篇和上一篇文章结合起来看,当写Hive UDF时,有两个选择:分别是继承UDF类和继承抽象类GenericUDF。这两种方法不同之处在于GenericUDF可以处理复杂类型参数,并且继承GenericUDF更加有效率。