hive版本:1.1.0-cdh5.14.0
上次开发udf还是在培训的时候,只记得需要集成udf然后实现evaluate方法就可以了,但是用到的这个版本有了较大的改动,开发udf需要 继承genericUDF,而之前的udf也变成了弃用udf;
genericUDF必须要实现的方法:
- initialize方法用于初始化,制定输入输出的类型
- evaluate方法表达数据的处理逻辑
- getDisplayString类似于java中的toString方法,在hive中以函数描述的内容展现(可以直接return children.toString()
下面记录下我这次开发的udf;
需要实现的是将ISO9601的时间格式化为东8区的时间格式,这里直接得到timestamp,代码如下:
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.Text;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
public class O2FormatTime extends GenericUDF {
//声明全局输入变量
ObjectInspector oTime;
//声明输出变量
private final Text text = new Text();
public ObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException {
oTime = args[0];
return PrimitiveObjectInspectorFactory.writableStringObjectInspector;
}
public Object evaluate(DeferredObject[] arguments) throws HiveException {
String isoTimeStr = arguments[0].get().toString();
if (StringUtils.isBlank(isoTimeStr)) {
System.out.println("iso9601 time is null");
return null;
}
byte[] formatedTimeStr = isoStr2utc8Str(isoTimeStr).getBytes();
text.clear();
text.append(formatedTimeStr,0,formatedTimeStr.length);
return text;
}
public String getDisplayString(String[] children) {
return children.toString();
}
/**
* 将格式为ISO9601的时间字符串转为标准时间格式
* @param isoStr iso9601时间字符串
* @return 标准时间字符串
*/
public static String isoStr2utc8Str(String isoStr){
// TODO 解析,格式化时间字符串
/*DateTimeFormatter isoformat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
DateTime dt= isoformat.parseDateTime(isoStr);
DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
return dt.toString(format);*/
// 转为东8区的时间
/*String formatTime = DateTime.parse(isoStr)
.withZone(DateTimeZone.forID("+08:00"))
.toString("yyyy-MM-dd HH:mm:ss.SSS");*/
//转换为东8区的timestamp
long timestampL = DateTime.parse(isoStr)
.withZone(DateTimeZone.forID("+08:00")).getMillis();
String timestamp = String.valueOf(timestampL/1000);
return timestamp;
}
}
这里用到了一个jodatime的时间处理包,特别好用;
需要注意的是在定义输入和输出值类型的时候需要用hadoop的类型以便在集群中传输,比如这里的额String就需要包装成Text