Hive UDAF(User- Defined Aggregation Funcation)用户自定义聚合函数是一个很好的功能,集成了先进的数据处理。hive有两种UDAF:简单和通用。顾名思义,简单的UDAF,写的相当简单的,但因为使用Java反射导致性能损失,而且有些特性不能使用,如可变长度参数列表。通用UDAF可以使用所有功能,但是UDAF就写的比较复杂,不直观。
1、一下两个包是必须的import org.apache.Hadoop.hive.ql.exec.UDAF和org.apache.hadoop.hive.ql.exec.UDAFEvaluator。
2、函数类需要继承UDAF类,内部类Evaluator实UDAFEvaluator接口。
3、Evaluator需要实现 init、iterate、terminatePartial、merge、terminate这几个函数。
a)init函数实现接口UDAFEvaluator的init函数。
b)iterate接收传入的参数,并进行内部的轮转。其返回类型为boolean。
c)terminatePartial无参数,其为iterate函数轮转结束后,返回轮转数据,terminatePartial类似于hadoop的Combiner。
d)merge接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean。
e)terminate返回最终的聚集函数结果。
package com.qiyi.headline.hive.udaf;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Comparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Function: Merge dimensions by count.
*/
public class MergeDimensions extends UDAF {
public static class MergeDimensionsEvaluator implements UDAFEvaluator {
private Map<String, Integer> partial;
private static final Logger LOGGER = LoggerFactory.getLogger(MergeDimensions.class);
public MergeDimensionsEvaluator() {
super();
init();
}
@Override
public void init() {
partial = new HashMap<String, Integer>();
}
public void addChannel(String channelId, Integer count) {
Integer originalCount = partial.get(channelId);
if (originalCount != null) {
originalCount += count;
} else {
originalCount = count;
}
partial.put(channelId, originalCount);
}
public boolean iterate(ArrayList<String> channels) {
if (channels == null) return true;
for (String channelId : channels) {
if (channelId == null) continue;
if (channelId.trim().equals("")) continue;
addChannel(channelId, 1);
}
return true;
}
public Map<String, Integer> terminatePartial() {
return partial;
}
public boolean merge(Map<String, Integer> other) {
if (other == null) return true;
for (Map.Entry<String, Integer> entry : other.entrySet()) {
addChannel(entry.getKey(), entry.getValue());
}
return true;
}
public Map<String, Integer> terminate() {
return partial;
}
}
}