1、UDF:用户定义(普通)函数,只对单行数值产生作用;
- 实现方法:
- 继承UDF类
- 重写evaluate方法
/**
* @function 自定义UDF统计最小值
* @author John
*
*/
public class Min extends UDF {
public Double evaluate(Double a, Double b) {
if (a == null)
a = 0.0;
if (b == null)
b = 0.0;
if (a >= b) {
return b;
} else {
return a;
}
}
}
2、UDAF:User- Defined Aggregation Funcation;用户定义聚合函数,可对多行数据产生作用;等同与SQL中常用的SUM(),AVG(),也是聚合函数;
-
实现方法:
1、用户的UDAF必须继承了org.apache.hadoop.hive.ql.exec.UDAF;2、用户的UDAF必须包含至少一个实现了org.apache.hadoop.hive.ql.exec的静态类,诸如实现了 UDAFEvaluator
3、一个计算函数必须实现的5个方法的具体含义如下:
init():主要是负责初始化计算函数并且重设其内部状态,一般就是重设其内部字段。一般在静态类中定义一个内部字段来存放最终的结果。
iterate():每一次对一个新值进行聚集计算时候都会调用该方法,计算函数会根据聚集计算结果更新内部状态。当输 入值合法或者正确计算了,则 就返回true。
terminatePartial():Hive需要部分聚集结果的时候会调用该方法,必须要返回一个封装了聚集计算当前状态的对象。
merge():Hive进行合并一个部分聚集和另一个部分聚集的时候会调用该方法。
terminate():Hive最终聚集结果的时候就会调用该方法。计算函数需要把状态作为一个值返回给用户。
4、部分聚集结果的数据类型和最终结果的数据类型可以不同。
package hive.udaf;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
public class Avg extends UDAF {
public static class AvgState {
private long mCount;
private double mSum;
}
public static class AvgEvaluator implements UDAFEvaluator {
AvgState state;
public AvgEvaluator() {
super();
state = new AvgState();
init();
}
/**
* init函数类似于构造函数,用于UDAF的初始化
*/
public void init() {
state.mSum = 0;
state.mCount = 0;
}
/**
* iterate接收传入的参数,并进行内部的轮转。其返回类型为boolean * * @param o * @return
*/
public boolean iterate(Double o) {
if (o != null) {
state.mSum += o;
state.mCount++;
}
return true;
}
/**
* terminatePartial无参数,其为iterate函数遍历结束后,返回轮转数据, * terminatePartial类似于hadoop的Combiner * * @return
*/
public AvgState terminatePartial() {
// combiner
return state.mCount == 0 ? null : state;
}
/**
* merge接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean * * @param o * @return
*/
public boolean merge(AvgState avgState) {
if (avgState != null) {
state.mCount += avgState.mCount;
state.mSum += avgState.mSum;
}
return true;
}
/**
* terminate返回最终的聚集函数结果 * * @return
*/
public Double terminate() {
return state.mCount == 0 ? null : Double.valueOf(state.mSum / state.mCount);
}
}
}
3、UDTF:User-Defined Table-Generating Functions,用户定义表生成函数,用来解决输入一行输出多行;
- 实现方法:
-
继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
-
initialize():UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)
-
process:初始化完成后,会调用process方法,真正的处理过程在process函数中,在process中,每一次forward() 调用产生一行;如果产生多列 可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数
-
最后close()方法调用,对需要清理的方法进行清理
import java.util.ArrayList;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
//切分”key:value;key:value;”这种字符串,返回结果为key, value两个字段
public class ExplodeMap extends GenericUDTF{
@Override
public void close() throws HiveException {
// TODO Auto-generated method stub
}
@Override
public StructObjectInspector initialize(ObjectInspector[] args)
throws UDFArgumentException {
if (args.length != 1) {
throw new UDFArgumentLengthException("ExplodeMap takes only one argument");
}
if (args[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentException("ExplodeMap takes string as a parameter");
}
ArrayList<String> fieldNames = new ArrayList<String>();
ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
fieldNames.add("col1");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
fieldNames.add("col2");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,fieldOIs);
}
@Override
public void process(Object[] args) throws HiveException {
String input = args[0].toString();
String[] test = input.split(";");
for(int i=0; i<test.length; i++) {
try {
String[] result = test[i].split(":");
forward(result);
} catch (Exception e) {
continue;
}
}
}
}
UDTF有两种使用方法,一种直接放到select后面,一种和lateral view一起使用
- 1:直接select中使用
select explode_map(properties) as (col1,col2) from src;
不可以添加其他字段使用
select a, explode_map(properties) as (col1,col2) from src
不可以嵌套调用
select explode_map(explode_map(properties)) from src
不可以和group by/cluster by/distribute by/sort by一起使用
select explode_map(properties) as (col1,col2) from src group by col1, col2
- 2:和lateral view一起使用
select src.id, mytable.col1, mytable.col2 from src lateral view explode_map(properties) mytable as col1, col2;