Hive学习之自己定义聚合函数
Hive支持用户自己定义聚合函数(UDAF),这样的类型的函数提供了更加强大的数据处理功能。
Hive支持两种类型的UDAF:简单型和通用型。正如名称所暗示的,简单型UDAF的实现很easy,但因为使用了反射的原因会出现性能的损耗,而且不支持长度可变的參数列表等特征。而通用型UDAF尽管支持长度可变的參数等特征。但不像简单型那么easy编写。
这篇文章将学习编写UDAF的规则,比方须要实现哪些接口,继承哪些类,定义哪些方法等。 实现通用型UDAF须要编写两个类:解析器和计算器。解析器负责UDAF的參数检查。操作符的重载以及对于给定的一组參数类型查找正确的计算器。计算器实现实际UDAF的计算逻辑。通常解析器能够实现org.apache.hadoop.hive.ql.udf.generic.GenericUDAFResolver2接口,但建议继承org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver抽象类,该类实现了GenericUDAFResolver2接口。计算器须要继承org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator抽象类。并做为解析器的内部静态类实现。
解析器的类型检查确保用户传递正确的參数。比方UDAF的參数为Integer类型。那么用户传递Double就须要抛出异常。操作符重载则同意为不同类型的參数定义不同的UDAF逻辑。
在编码之前。先了解一下AbstractGenericUDAFResolver类,该类有两个重载的方法public GenericUDAFEvaluator getEvaluator(GenericUDAFParameterInfoinfo)和public GenericUDAFEvaluatorgetEvaluator(TypeInfo[]
info),当中前者不再建议使用,这样继承该类时仅仅覆盖第二个方法就可以。
该方法的參数类型为TypeInfo[],返回值为GenericUDAFEvaluator。在该方法中完毕參数的检查,不仅包括參数的数量还有參数的类型。TypeInfo位于包org.apache.hadoop.hive.serde2.typeinfo中。该类存储类型信息。Hive眼下支持5种类型:基本类型(String。Number等)、List对象、Map对象、Struct对象和Union对象。
该类的getCategory()方法返回类型信息的类别。详细为枚举类ObjectInspector.Category,该枚举类包括了相应上述5种类型的枚举常量,分别为:PRIMITIVE、LIST、MAP、STRUCT和UNION。getEvaluator(TypeInfo[]
info)的详细实现例如以下:
@Override
public GenericUDAFEvaluator getEvaluator(TypeInfo[] parameters)
throws SemanticException {
if (parameters.length != 1) {
throw new UDFArgumentTypeException(parameters.length - 1,
"Exactly one argument is expected.");
}
ObjectInspector oi = TypeInfoUtils.getStandardJavaObjectInspectorFromTypeInfo(parameters[0]);
if (!ObjectInspectorUtils.compareSupported(oi)) {
throw new UDFArgumentTypeException(parameters.length - 1,
"Cannot support comparison of map<> type or complex type containing map<>.");
}
return new GenericUDAFMaxEvaluator();
}
假设想实现操作符重载,须要创建与操作符数目同样的计算器内部类,比方有两个重载方法,那么须要创建两个计算器,然后依据输入參数的不同返回不同的计算器。
正如上面提到的计算器须要继承org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator抽象类。该类提供了几个须要被子类实现的抽象方法。这些方法建立了处理UDAF语义的过程。在详细学习怎样编写计算器之前,先了解一下计算器的4种模式,这些模式由枚举类GenericUDAFEvaluator.Mode定义:
public static enum Mode {
PARTIAL1,
PARTIAL2,
FINAL,
COMPLETE
};
PARTIAL1模式是从原始数据到部分聚合数据的过程,将调用方法iterate() 和terminatePartial()。PARTIAL2模式是从部分聚合数据到部分聚合数据的过程。将调用方法merge() 和terminatePartial()。FINAL模式是从部分聚合到所有聚合的过程,将调用merge()和 terminate()。最后一种模式为COMPLETE,该模式为从原始数据直接到所有聚合的过程,将调用merge() 和 terminate()。
在了解了计算器的模式后。详细看看计算器必须实现的方法。
GenericUDAFEvaluator类提供了以下几个抽象方法:
- getNewAggregationBuffer():用于返回存储暂时聚合结果的 GenericUDAFEvaluator.AggregationBuffer对象。
- reset(GenericUDAFEvaluator.AggregationBuffer agg):重置聚合,该方法在重用同样的聚合时非常实用。
- iterate(GenericUDAFEvaluator.AggregationBuffer agg,Object[] parameters):迭代parameters表示的原始数据并保存到agg中。
- terminatePartial(GenericUDAFEvaluator.AggregationBuffer agg):以持久化的方式返回agg表示部分聚合结果,这里的持久化意味着返回值仅仅能Java基础类型、数组、基础类型包装器、Hadoop的Writables、Lists和Maps。即使实现了java.io.Serializable,也不要使用自己定义的类。
- merge(GenericUDAFEvaluator.AggregationBuffer agg,Object partial):合并由partial表示的部分聚合结果到agg中。
- terminate(GenericUDAFEvaluator.AggregationBuffer agg):返回由agg表示的终于结果。
除了上述抽象方法,GenericUDAFEvaluato另一个尽管不是抽象方法但通常也须要覆盖的方法ObjectInspector
init(GenericUDAFEvaluator.Mode m,ObjectInspector[] parameters),该方法用于初始化计算器,在不同的模式下第二參数的含义是不同的,比方m为PARTIAL1 和 COMPLETE时,第二个參数为原始数据。m为PARTIAL2 和 FINAL时。该參数仅为部分聚合数据(该数组总是仅仅有一个元素)。在PARTIAL1和PARTIAL2模式下,ObjectInspector 用于terminatePartial方法的返回值,在FINAL和COMPLETE模式下ObjectInspector 用于terminate方法的返回值。
上述这些方法基本依照init、getNewAggregationBuffer、iterate、terminatePartial、merge、terminate的顺序调用。另一点须要明白的是聚合计算必须在数据上是随意可分的。
能够參考Hive自带的聚合函数。比方求最大值的max函数,其计算器的源码例如以下所看到的。
在计算器中必须注意的是ObjectInspector及其子类的使用。该类表示特定的类型及怎样在内存中存储该类型的数据,详细的用法能够參考API。
public static class GenericUDAFMaxEvaluator extends GenericUDAFEvaluator {
private transient ObjectInspector inputOI;
private transient ObjectInspector outputOI;
@Override
public ObjectInspector init(Mode m, ObjectInspector[] parameters)
throws HiveException {
assert (parameters.length == 1);
super.init(m, parameters);
inputOI = parameters[0];
// Copy to Java object because that saves object creation time.
// Note that on average the number of copies is log(N) so that's not
// very important.
outputOI = ObjectInspectorUtils.getStandardObjectInspector(inputOI,
ObjectInspectorCopyOption.JAVA);
return outputOI;
}
/** class for storing the current max value */
static class MaxAgg extends AbstractAggregationBuffer {
Object o;
}
@Override
public AggregationBuffer getNewAggregationBuffer() throws HiveException {
MaxAgg result = new MaxAgg();
return result;
}
@Override
public void reset(AggregationBuffer agg) throws HiveException {
MaxAgg myagg = (MaxAgg) agg;
myagg.o = null;
}
boolean warned = false;
@Override
public void iterate(AggregationBuffer agg, Object[] parameters)
throws HiveException {
assert (parameters.length == 1);
merge(agg, parameters[0]);
}
@Override
public Object terminatePartial(AggregationBuffer agg)
throws HiveException {
return terminate(agg);
}
@Override
public void merge(AggregationBuffer agg, Object partial)
throws HiveException {
if (partial != null) {
MaxAgg myagg = (MaxAgg) agg;
int r = ObjectInspectorUtils.compare(myagg.o, outputOI, partial, inputOI);
if (myagg.o == null || r < 0) {
myagg.o = ObjectInspectorUtils.copyToStandardObject(partial, inputOI,ObjectInspectorCopyOption.JAVA);
}
}
}
@Override
public Object terminate(AggregationBuffer agg) throws HiveException {
MaxAgg myagg = (MaxAgg) agg;
return myagg.o;
}
}
Hive学习之自己定义聚合函数的更多相关文章
- MongoDB学习总结(三) —— 常用聚合函数
上一篇介绍了MongoDB增删改查命令的基本用法,这一篇来学习一下MongoDB的一些基本聚合函数. 下面我们直奔主题,用简单的实例依次介绍一下. > count() 函数 集合的count函数 ...
- Mongodb学习笔记四(Mongodb聚合函数)
第四章 Mongodb聚合函数 插入 测试数据 ;j<;j++){ for(var i=1;i<3;i++){ var person={ Name:"jack"+i, ...
- Oracle学习(十一)聚合函数
AVG() 求平均数 --查询某列的平均值 SELECT AVG(列) FROM 表 COUNT()查询条数 -- 查询所有记录的条数 select count(*) from 表; -- 查询对应列 ...
- hive 学习系列四(用户自定义函数)
如果入参是简单的数据类型,直接继承UDF,实现一个或者多个evaluate 方法. 具体流程如下: 1,实现大写字符转换成小写字符的UDF package com.example.hive.udf; ...
- 9.hive聚合函数,高级聚合,采样数据
本文主要使用实例对Hive内建的一些聚合函数.分析函数以及采样函数进行比较详细的讲解. 一.基本聚合函数 数据聚合是按照特定条件将数据整合并表达出来,以总结出更多的组信息.Hive包含内建的一些基本聚 ...
- MySQL数据库聚合函数
+++++++++++++++++++++++++++++++++++++++++++标题:MySQL数据库聚合函数时间:2019年2月25日内容:MySQL数据库聚合函数重点:MySQL数据库聚合函 ...
- LitePal的聚合函数
传统的聚合函数用法 虽说是聚合函数,但它的用法其实和传统的查询还是差不多的,即仍然使用的是select语句.但是在select语句当中我们通常不会再去指定列名,而是将需要统计的列名传入到聚合函数当 ...
- 【Python笔记】2020年7月22日练习=[定义一个函数quadratic(a, b, c),接收3个参数,返回一元二次方程的两个解]
学习教程:廖雪峰-Python教程-函数-函数定义 学习记录:[定义一个函数quadratic(a, b, c),接收3个参数,返回一元二次方程的两个解] 学习心得: 1.对问题进行判断分析后再下手. ...
- hive学习笔记之十:用户自定义聚合函数(UDAF)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<hive学习笔记>的第十 ...
随机推荐
- Servlet 3.0 新特性详解
转自:http://www.ibm.com/developerworks/cn/java/j-lo-servlet30/#major3 Servlet 是 Java EE 规范体系的重要组成部分,也是 ...
- Linux系统运维笔记(二),Linux文件编辑命令
Linux系统运维笔记 Linux文件编辑命令 首先我们使用命令 vi filename 打开一个文件,这个时候进入到的是命令模式 接下来我们按i,然后键盘随便输入写内容. 然后按ESC重新进入到命令 ...
- Webpack vs Gulp
Webpack vs Gulp 谁会被拍死在沙滩上 本文组织结构 理想的前端开发流程 Gulp 为何物 Webpack 又是从哪冒出来的 结论 文章有点长,总共 1800 字,阅读需要 18 分钟 ...
- 【AtCoder】ARC090
C - Candies 前一枚举一个i,求第一行的前i个和第二行从第n个到第i个 代码 #include <bits/stdc++.h> #define fi first #define ...
- P1020 导弹拦截 dp 树状数组维护最长升序列
题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...
- 关于 win10 创建WiFi热点 问题(无法启动承载网络 , 我们无法设置移动热点,因为你的电脑未建立以太网,wifi或手机网络数据连接 )
电脑创建WiFi,一般三种办法: 1. WiFi共享软件:猎豹wifi.wifi共享精灵.wifi共享大师..... 2. 命令提示符 netsh wlan set hostednetwork mod ...
- 001.Chrony时间服务器
一 Chrony概览 1.1 Chrony简介 Chrony是一个开源的自由软件,是网络世界协议(NTP)的另一种实现,它能保持系统时钟与时钟服务器(NTP)同步,让时间保持精确. 它由两个程序组成: ...
- 开发人员如何正确对待BUG?
1.前端开发与后端开发 出了问题,最重要的是先找到方法迅速解决,而不是去互相指责.前端存在这样的思维模式,后端也存在这样的思维模式,这种思维模式不太好.出了问题,最好先检查一下自己,反省是不是自己这 ...
- 【BZOJ 1211】 1211: [HNOI2004]树的计数 (prufer序列、计数)
1211: [HNOI2004]树的计数 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2468 Solved: 868 Description 一 ...
- SDOI2013 R1 Day1
目录 2018.3.22 Test 总结 T1 BZOJ.3122.[SDOI2013]随机数生成器(BSGS 等比数列) T2 BZOJ.3123.[SDOI2013]森林(主席树 启发式合并) T ...