hive-基础-UDAF概述
UDF
@Description(name = "Upper()",
value = "_FUNC_(originArray,trimStr) " +
"Remove the trimStr value of originArray . Returns NULL if originArray is NULL." +
"Returns null if elementStr is not found in originArray or is NULL."
)
public class Upper extends UDF {
public String evaluate(String str1, String str2) {
try {
return str1.toUpperCase()+"&&"+str2;
} catch (Exception e) {
return null;
}
}
}
然后执行
add jar /home/sean/workspace/zsh-udf/zsh-demo-udf.jar;
create temporary function upper as 'Upper';
select upper(t.col1) from t limit 10;
drop temporary function upper;
delete jar /home/sean/workspace/zsh-udf/zsh-demo-udf.jar;
UDAF
UDAF和group by一起使用
resolver:resolver负责类型检查,操作符重载
evaluator:UDAF逻辑
resolver(继承AbstractGenericUDAFResolver)
大体框架
public class GenericUDAFSum extends AbstractGenericUDAFResolver {
static final Log LOG = LogFactory.getLog(GenericUDAFSum.class.getName());
@Override
public GenericUDAFEvaluator getEvaluator(TypeInfo[] parameters)
throws SemanticException {
// Type-checking goes here!
return new GenericUDAFSumLong();
}
public static class GenericUDAFSumLong extends GenericUDAFEvaluator {
// UDAF logic goes here!
}
}
第一行创建LOG对象,用来写入警告和错误到hive的log;
继承AbstractGenericUDAFResolver之后,只需要重写getEvaluator,根据SQL传入的参数返回正确的evaluator,这里是为了实现运算符的重载;
getEvaluator的完整代码如下,这个方法返回的一堆就是后面要实现的
public class GenericUDAFSum extends AbstractGenericUDAFResolver {
@Override
public GenericUDAFEvaluator getEvaluator(TypeInfo[] parameters)
throws SemanticException {
if (parameters.length != 1) {
throw new UDFArgumentTypeException(parameters.length - 1,
"Exactly one argument is expected.");
}
if (parameters[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentTypeException(0,
"Only primitive type arguments are accepted but "
+ parameters[0].getTypeName() + " is passed.");
}
switch (((PrimitiveTypeInfo) parameters[0]).getPrimitiveCategory()) {
case BYTE:
case SHORT:
case INT:
case LONG:
case TIMESTAMP:
return new GenericUDAFSumLong();
case FLOAT:
case DOUBLE:
case STRING:
return new GenericUDAFSumDouble();
case BOOLEAN:
default:
throw new UDFArgumentTypeException(0,
"Only numeric or string type arguments are accepted but "
+ parameters[0].getTypeName() + " is passed.");
}
public static class GenericUDAFSumLong extends GenericUDAFEvaluator {
...
}
}
如果不是原生类型(即符合类型,array,map此类),则抛出异常;
还实现了操作符重载,对于整数类型,使用GenericUDAFSumLong实现UDAF的逻辑;
对于浮点类型,使用GenericUDAFSumDouble实现UDAF的逻辑。
这里一共返回:GenericUDAFSumLong和GenericUDAFSumDouble这两种情况,这两种GenericUDAFSumEvaluator;
evaluator
继承抽象类GenericUDAFEvaluator,内部类Mode如下
public static enum Mode {
/**
* PARTIAL1: 这个是mapreduce的map阶段:从原始数据到部分数据聚合
* 将会调用iterate()和terminatePartial()
*/
PARTIAL1,
/**
* PARTIAL2: 这个是mapreduce的map端的Combiner阶段,负责在map端合并map的数据::从部分数据聚合到部分数据聚合:
* 将会调用merge() 和 terminatePartial()
*/
PARTIAL2,
/**
* FINAL: mapreduce的reduce阶段:从部分数据的聚合到完全聚合
* 将会调用merge()和terminate()
*/
FINAL,
/**
* COMPLETE: 如果出现了这个阶段,表示mapreduce只有map,没有reduce,所以map端就直接出结果了:从原始数据直接到完全聚合
* 将会调用 iterate()和
* ()
*/
COMPLETE
};
evaluator必须实现的方法
1、getNewAggregationBuffer():返回存储临时聚合结果的AggregationBuffer对象。
2、reset(AggregationBuffer agg):重置聚合结果对象,以支持mapper和reducer的重用。
3、iterate(AggregationBuffer agg,Object[] parameters):迭代处理原始数据parameters并保存到agg中。
4、terminatePartial(AggregationBuffer agg):以持久化的方式返回agg表示的部分聚合结果,这里的持久化意味着返回值只能Java基础类型、数组、基础类型包装器、Hadoop的Writables、Lists和Maps。
5、merge(AggregationBuffer agg,Object partial):合并由partial表示的部分聚合结果到agg中。
6、terminate(AggregationBuffer agg):返回最终结果。
还可以覆盖初始化方法
ObjectInspector init(Mode m,ObjectInspector[] parameters)
不同模式下parameters含义不同
#parameters的作用
PARTIAL1、COMPLETE ---> parameters为原始数据
PARTIAL2、FINAL ---> parameters为部分聚合数据,只有一个元素
#ObjectInspector的作用
PARTIAL1、PARTIAL2 --> ObjectInspector用于terminatePartial方法的返回值
FINAL、COMPLETE ---> ObjectInspector 用于terminate方法的返回值
实现UDAF是一个完整的mapreduce过程
有mapper和reducer ---> 会经历PARTIAL1(mapper),FINAL(reducer)过程
有combiner ---> 经历PARTIAL1(mapper),PARTIAL2(combiner),FINAL(reducer)
只有map没有reduce ---> 只有COMPLETE (直接输入原始数据出结果)
GenericUDAFSumLong的evaluator例子
public static class GenericUDAFSumLong extends GenericUDAFEvaluator {
private PrimitiveObjectInspector inputOI;
private LongWritable result;
//这个方法返回了UDAF的返回类型,这里确定了sum自定义函数的返回类型是Long类型
@Override
public ObjectInspector init(Mode m, ObjectInspector[] parameters) throws HiveException {
assert (parameters.length == 1);
super.init(m, parameters);
result = new LongWritable(0);
inputOI = (PrimitiveObjectInspector) parameters[0];
return PrimitiveObjectInspectorFactory.writableLongObjectInspector;
}
/** 存储sum的值的类 */
static class SumLongAgg implements AggregationBuffer {
boolean empty;
long sum;
}
//创建新的聚合计算的需要的内存,用来存储mapper,combiner,reducer运算过程中的相加总和。
@Override
public AggregationBuffer getNewAggregationBuffer() throws HiveException {
SumLongAgg result = new SumLongAgg();
reset(result);
return result;
}
//mapreduce支持mapper和reducer的重用,所以为了兼容,也需要做内存的重用。
@Override
public void reset(AggregationBuffer agg) throws HiveException {
SumLongAgg myagg = (SumLongAgg) agg;
myagg.empty = true;
myagg.sum = 0;
}
private boolean warned = false;
//map阶段调用,只要把保存当前和的对象agg,再加上输入的参数,就可以了。
@Override
public void iterate(AggregationBuffer agg, Object[] parameters) throws HiveException {
assert (parameters.length == 1);
try {
merge(agg, parameters[0]);
} catch (NumberFormatException e) {
if (!warned) {
warned = true;
LOG.warn(getClass().getSimpleName() + " "
+ StringUtils.stringifyException(e));
}
}
}
//mapper结束要返回的结果,还有combiner结束返回的结果
@Override
public Object terminatePartial(AggregationBuffer agg) throws HiveException {
return terminate(agg);
}
//combiner合并map返回的结果,还有reducer合并mapper或combiner返回的结果。
@Override
public void merge(AggregationBuffer agg, Object partial) throws HiveException {
if (partial != null) {
SumLongAgg myagg = (SumLongAgg) agg;
myagg.sum += PrimitiveObjectInspectorUtils.getLong(partial, inputOI);
myagg.empty = false;
}
}
//reducer返回结果,或者是只有mapper,没有reducer时,在mapper端返回结果。
@Override
public Object terminate(AggregationBuffer agg) throws HiveException {
SumLongAgg myagg = (SumLongAgg) agg;
if (myagg.empty) {
return null;
}
result.set(myagg.sum);
return result;
}
}
需要继续阅读:GenericUDAFAverage

浙公网安备 33010602011771号