卷首语

前一篇文章hive UDAF开发入门和运行过程详解(转)里面讲过UDAF的开发过程,其中说到如果要深入理解UDAF的执行,可以看看求平均值的UDF的源码

本人在看完源码后,也还是没能十分理解里面的内容,于是动手再自己开发一个新的函数,试图多实践中理解它

函数功能介绍

函数的功能比较蛋疼,我们都知道Hive中有几个常用的聚合函数:sum,max,min,avg

现在要用一个函数来同时实现俩个不同的功能,对于同一个key,要求返回指定value集合中的最大值与最小值

这里面涉及到一个难点,函数接收到的数据只有一个,但是要同时产生出俩个新的数据出来,且具备一定的逻辑关系

语言描述这东西我不大懂,想了好久,还是直接上代码得了。。。。。。。。。。。。。

源码

package org.juefan.udaf;

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.parse.SemanticException;
import org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
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.StructField;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.DoubleObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.LongObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils;
import org.apache.hadoop.hive.serde2.typeinfo.PrimitiveTypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.util.StringUtils; /**
* GenericUDAFMaxMin.
*/
@Description(name = "maxmin", value = "_FUNC_(x) - Returns the max and min value of a set of numbers")
public class GenericUDAFMaxMin extends AbstractGenericUDAFResolver { static final Log LOG = LogFactory.getLog(GenericUDAFMaxMin.class.getName()); @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 FLOAT:
case DOUBLE:
case STRING:
case TIMESTAMP:
return new GenericUDAFMaxMinEvaluator();
case BOOLEAN:
default:
throw new UDFArgumentTypeException(0,
"Only numeric or string type arguments are accepted but "
+ parameters[0].getTypeName() + " is passed.");
}
} /**
* GenericUDAFMaxMinEvaluator.
*
*/
public static class GenericUDAFMaxMinEvaluator extends GenericUDAFEvaluator { // For PARTIAL1 and COMPLETE
PrimitiveObjectInspector inputOI; // For PARTIAL2 and FINAL
StructObjectInspector soi;
// 封装好的序列化数据接口,存储计算过程中的最大值与最小值
StructField maxField;
StructField minField;
// 存储数据,利用get()可直接返回double类型值
DoubleObjectInspector maxFieldOI;
DoubleObjectInspector minFieldOI; // For PARTIAL1 and PARTIAL2
// 存储中间的结果
Object[] partialResult; // For FINAL and COMPLETE
// 最终输出的数据
Text result; @Override
public ObjectInspector init(Mode m, ObjectInspector[] parameters)
throws HiveException {
assert (parameters.length == 1);
super.init(m, parameters); // 初始化数据输入过程
if (m == Mode.PARTIAL1 || m == Mode.COMPLETE) {
inputOI = (PrimitiveObjectInspector) parameters[0];
} else {
// 如果接收到的数据是中间数据,则转换成相应的结构体
soi = (StructObjectInspector) parameters[0];
// 获取指定字段的序列化数据
maxField = soi.getStructFieldRef("max");
minField = soi.getStructFieldRef("min");
// 获取指定字段的实际数据
maxFieldOI = (DoubleObjectInspector) maxField.getFieldObjectInspector();
minFieldOI = (DoubleObjectInspector) minField.getFieldObjectInspector();
} // 初始化数据输出过程
if (m == Mode.PARTIAL1 || m == Mode.PARTIAL2) {
// 输出的数据是一个结构体,其中包含了max和min的值
// 存储结构化数据类型
ArrayList<ObjectInspector> foi = new ArrayList<ObjectInspector>();
foi.add(PrimitiveObjectInspectorFactory.writableDoubleObjectInspector);
foi.add(PrimitiveObjectInspectorFactory.writableDoubleObjectInspector);
// 存储结构化数据的字段名称
ArrayList<String> fname = new ArrayList<String>();
fname.add("max");
fname.add("min");
partialResult = new Object[2];
partialResult[0] = new DoubleWritable(0);
partialResult[1] = new DoubleWritable(0);
return ObjectInspectorFactory.getStandardStructObjectInspector(fname,
foi); } else {
// 如果执行到了最后一步,则指定相应的输出数据类型
result = new Text("");
return PrimitiveObjectInspectorFactory.writableStringObjectInspector;
}
} static class AverageAgg implements AggregationBuffer {
double max;
double min;
}; @Override
public AggregationBuffer getNewAggregationBuffer() throws HiveException {
AverageAgg result = new AverageAgg();
reset(result);
return result;
} @Override
public void reset(AggregationBuffer agg) throws HiveException {
AverageAgg myagg = (AverageAgg) agg;
myagg.max = Double.MIN_VALUE;
myagg.min = Double.MAX_VALUE;
} boolean warned = false; @Override
public void iterate(AggregationBuffer agg, Object[] parameters)
throws HiveException {
assert (parameters.length == 1);
Object p = parameters[0];
if (p != null) {
AverageAgg myagg = (AverageAgg) agg;
try {
// 获取输入数据,并进行相应的大小判断
double v = PrimitiveObjectInspectorUtils.getDouble(p, inputOI);
if(myagg.max < v){
myagg.max = v;
}
if(myagg.min > v){
myagg.min = v;
}
} catch (NumberFormatException e) {
if (!warned) {
warned = true;
LOG.warn(getClass().getSimpleName() + " "
+ StringUtils.stringifyException(e));
LOG.warn(getClass().getSimpleName()
+ " ignoring similar exceptions.");
}
}
}
} @Override
public Object terminatePartial(AggregationBuffer agg) throws HiveException {
// 将中间计算出的结果封装好返回给下一步操作
AverageAgg myagg = (AverageAgg) agg;
((DoubleWritable) partialResult[0]).set(myagg.max);
((DoubleWritable) partialResult[1]).set(myagg.min);
return partialResult;
} @Override
public void merge(AggregationBuffer agg, Object partial)
throws HiveException {
if (partial != null) {
//此处partial接收到的是terminatePartial的输出数据
AverageAgg myagg = (AverageAgg) agg;
Object partialmax = soi.getStructFieldData(partial, maxField);
Object partialmin = soi.getStructFieldData(partial, minField);
if(myagg.max < maxFieldOI.get(partialmax)){
myagg.max = maxFieldOI.get(partialmax);
}
if(myagg.min > minFieldOI.get(partialmin)){
myagg.min = minFieldOI.get(partialmin);
}
}
} @Override
public Object terminate(AggregationBuffer agg) throws HiveException {
// 将最终的结果合并成字符串后输出
AverageAgg myagg = (AverageAgg) agg;
if (myagg.max == 0) {
return null;
} else {
result.set(myagg.max + "\t" + myagg.min);
return result;
}
}
} }

写完后还是觉得没有怎么理解透整个过程,所以上面的注释也就将就着看了,不保证一定正确的!

下午加上一些输出跟踪一下执行过程才行,不过代码的逻辑是没有问题的了,本人运行过!

Hive UDAF开发之同时计算最大值与最小值的更多相关文章

  1. hive UDAF开发入门和运行过程详解(转)

    介绍 hive的用户自定义聚合函数(UDAF)是一个很好的功能,集成了先进的数据处理.hive有两种UDAF:简单和通用.顾名思义,简单的UDAF,写的相当简单的,但因为使用Java反射导致性能损失, ...

  2. Hive UDAF开发详解

    说明 这篇文章是来自Hadoop Hive UDAF Tutorial - Extending Hive with Aggregation Functions:的不严格翻译,因为翻译的文章示例写得比较 ...

  3. hive UDAF开发和运行全过程

    介绍 hive的用户自定义聚合函数(UDAF)是一个很好的功能,集成了先进的数据处理.hive有两种UDAF:简单和通用.顾名思义,简单的UDAF,写的相当简单的,但因为使用Java反射导致性能损失, ...

  4. pyspark计算最大值、最小值、平均值

    需求:使用pyspark计算相同key的最大值.最小值.平均值 说明: 最大值和最小值好计算,直接reduceByKey后使用python内置的max.min方法 平均值计算提供两种计算方法,直接先上 ...

  5. awk计算最大值,最小值,平均值的脚本

    传入至少三个数字参数到脚本awk_file,并计算出最大,最小,平均值.需要判断传入的数字是否足够,否则输出警告信息.平均值保留两位小数. 如执行bash awk_file 3 4 6 5,脚本输出结 ...

  6. NumPy实现数据的聚合,计算最大值,最小值

    1.数组值的求和 首先构造一个具有100个值的数组,然后我们利用两个不同的方法进行求和: >>> l=np.random.random() l的数据如下: >>> ...

  7. shell脚本,通过传入的参数来计算最大值和最小值以及平均值。

    [root@localhost zuoye]# cat quansges.sh #!/bin/bash > file [ ! $# -ge ] && || echo $* > ...

  8. c++11之 algorithm 算法库新增 minmax_element同时计算最大值和最小值

    0.时刻提醒自己 Note: vector的释放 1. minmax_element 功能 寻找范围 [first, last) 中最小和最大的元素. 2. 头文件 #include <algo ...

  9. Hive UDAF介绍与开发

    UDAF简介 UDAF是用户自定义聚合函数.Hive支持其用户自行开发聚合函数完成业务逻辑. 通俗点说,就是你可能需要做一些特殊的甚至是非常扭曲的逻辑聚合,但是Hive自带的聚合函数不够玩,同时也还找 ...

随机推荐

  1. 读取xml文件"分析 EntityName 时出错"的解决方案

    在涉及到xml与xslt编程的过程中,经常会碰到"分析 EntityName 时出错"的提示,这个不是程序错误,是因为xml文件中使用了一些特殊符号导致的.    XML 节点中不 ...

  2. 《STL源代码分析》---stl_list.h读书笔记

    STL在列表list它是一种经常使用的容器.list不连续双向链表在内存,而且是环形. 理解列表如何操作的详细信息,然后.阅读STL名单上的代码是最好的方法. G++ 2.91.57.cygnus\c ...

  3. Android环境结构--安装Eclipse错

    在学习安卓第一步.成立了一个开发环境. 经验,知道,所以这一步是不容易,因为你觉得,我可能是太幸运了. 我见到 题. 首先,安装Eclipse的时候. [Problem 1] [问题原因]: (1) ...

  4. EF4.1: Add/Attach and Entity States(EF中的实体状态转换说明)

    实体的状态,连接以及 SaveChanges 方法 数据库上下文对象维护内存中的对象与数据库中数据行之间的同步.这些信息在调用 SaveChanges方法被调用的时候使用.例如,当使用 Add 方法传 ...

  5. 通过私有协议Chrome浏览器页面打开本地程序

    近期方有这样的要求:这两个系统,根据一组Chrome开展,根据一组IE开展,需要Chrome添加一个链接,然后进入IE该系统的开发.这,需要Chrome跳转到创建一个链接IE浏览器指定的页面.同时也实 ...

  6. 大约HR升级版的设计为组汇总

    该公司刚刚完成HR系统升级,系统从单一公司实现使用更多的公司使用变更.在一个月的时间升级,虽然很苦,但他们自己的系统架构的感觉获益,有以下的详细的见解: 一.MVC还是非常重要 系统框架是五年前用de ...

  7. InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布

    原文:InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布 原帖地址:http://blog.csdn.net/fishout/archive/2009/10/ ...

  8. sb2-admin

    近期开发中遇到的问题总结   最近准备把后台管理系统重新设计开发下,使用了bootstrap,在网上找了个漂亮的后台模板:sb2-admin,在使用中遇到了不少问题,总结下,以免以后忘记. 1.EF5 ...

  9. iOS文档序列化(对象归档)

    对象归档: 概念: 对象归档是指将对象写入文件保存在硬盘,当再次又一次打开程序时,能够还原这些对象.也称:对象序列化.对象持久化. 数据持久性的方式(事实上就是3类) 1,NSKeyedArchive ...

  10. leetcode[67] Plus One

    题目:对一个用vector存的数字进行加1,然后返回加1后的值. 一次就在oj上通过了. 就是进位加上当前位如果大于9,那就当前位等于0: 随后进位还为1的话就是在数组前面插入一个1: class S ...