HIVE UDAF开发上手,你一看就懂!

单机跑一个脚本做数据处理,但是由于输入数据实在太大,处理过程中占用大量内存经常被系统杀死,所以考虑放在hive中做数据聚合。借此机会研究下UDAF怎么写,把踏坑的经验写出来,希望可以帮助大家少走弯路!嗯。。。就酱紫。

经常听UDF,那么UDAF是什么鬼? 就是聚合功能的UDF啦~  比如hive内置的 count、sum、max、min、avg等。 但是内置的函数其实并不能满足我们复杂的统计需求,就需要自己去实现一个方法。

有两种实现方法,一种简单的,一种通用的,简单的方法据说有性能问题,我们就直接看通用的实现方法吧~

实现一个Generic UDAF有两部分:

  1. resolver
  2. evaluator

这俩货分别对应以下两个抽象类:

import org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator;

resolver 主要用来做参数检查和操作符重载,我们可以根据输入参数的不同选择相应的evaluator

evaluator 则是实现主要逻辑的地方,以静态内部类的形式存在

#!Java
public class GenericUDAFHistogramNumeric extends AbstractGenericUDAFResolver {
  static final Log LOG = LogFactory.getLog(GenericUDAFHistogramNumeric.class.getName());

  @Override
  public GenericUDAFEvaluator getEvaluator(GenericUDAFParameterInfo info) throws SemanticException {
    // 参数检查

    return new GenericUDAFHistogramNumericEvaluator();
  }
  /**
   *这个静态内部类就是写我们自己逻辑的地方,这个类名根据需要改,这个是官方文档写的一个条形图的例子
   */
  public static class GenericUDAFHistogramNumericEvaluator extends GenericUDAFEvaluator {
    // UDAF 逻辑
  }
}

这里需要介绍下这个例子的功能:hIve中的histogram_numeric函数,用来做直方图的,比如我们要把年龄分30个桶构建直方图就是SELECT histogram_numeric(age, 30) FROM employees;

下面我们继续看例子

#!Java
  /**
  * 这个方法的参数新版的已经发生变化,直接就是TypeInfo [] parameters
  */
  public GenericUDAFEvaluator getEvaluator(GenericUDAFParameterInfo info) throws SemanticException {
    TypeInfo [] parameters = info.getParameters();
    if (parameters.length != 2) {
      throw new UDFArgumentTypeException(parameters.length - 1,
          "Please specify exactly two arguments.");
    }

    // 检查第一个参数类型,如果不是原始类型(基本类型)抛异常
    if (parameters[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
      throw new UDFArgumentTypeException(0,
          "Only primitive type arguments are accepted but "
          + parameters[0].getTypeName() + " was passed as parameter 1.");
    }
    switch (((PrimitiveTypeInfo) parameters[0]).getPrimitiveCategory()) {
    case BYTE:
    case SHORT:
    case INT:
    case LONG:
    case FLOAT:
    case DOUBLE:
      break;
    case STRING:
    case BOOLEAN:
    default:
      throw new UDFArgumentTypeException(0,
          "Only numeric type arguments are accepted but "
          + parameters[0].getTypeName() + " was passed as parameter 1.");
    }

    // 检查第二个参数类型,条形图桶编号,假设这里要求是整型数
    if (parameters[1].getCategory() != ObjectInspector.Category.PRIMITIVE) {
      throw new UDFArgumentTypeException(1,
          "Only primitive type arguments are accepted but "
          + parameters[1].getTypeName() + " was passed as parameter 2.");
    }
    // 如果不是整型,抛异常
    if( ((PrimitiveTypeInfo) parameters[1]).getPrimitiveCategory()
        != PrimitiveObjectInspector.PrimitiveCategory.INT) {
      throw new UDFArgumentTypeException(1,
          "Only an integer argument is accepted as parameter 2, but "
          + parameters[1].getTypeName() + " was passed instead.");
    }
    //返回对应的处理类
    return new GenericUDAFHistogramNumericEvaluator();
  }

然后我们看看evaluator

#!Java
  public static class GenericUDAFHistogramNumericEvaluator extends GenericUDAFEvaluator {

    // For PARTIAL1 and COMPLETE: ObjectInspectors for original data,这俩货是用来做类型转换的
    private PrimitiveObjectInspector inputOI;
    private PrimitiveObjectInspector nbinsOI;

    // For PARTIAL2 and FINAL: ObjectInspectors for partial aggregations (list of doubles)
    private StandardListObjectInspector loi;

    @Override
    public ObjectInspector init(Mode m, ObjectInspector[] parameters) throws HiveException {
      super.init(m, parameters);
      // return type goes here
    }

    @Override
    public Object terminatePartial(AggregationBuffer agg) throws HiveException {
      // return value goes here
    }

    @Override
    public Object terminate(AggregationBuffer agg) throws HiveException {
      // final return value goes here
    }

    @Override
    public void merge(AggregationBuffer agg, Object partial) throws HiveException {
    }

    @Override
    public void iterate(AggregationBuffer agg, Object[] parameters) throws HiveException {
    }

    // Aggregation buffer definition and manipulation methods
    static class StdAgg implements AggregationBuffer {
    };

    @Override
    public AggregationBuffer getNewAggregationBuffer() throws HiveException {
    }

    @Override
    public void reset(AggregationBuffer agg) throws HiveException {
    }
  }

理解这个类我们首先需要了解一些事情,写过Hadoop MapReduce 的同学应该知道,一个MapReduce job 分为  map、combine、reduce三个阶段,map阶段是把函数应用于输入数据的每一条,构建key-value供后续聚合;combine阶段是在mapper端局部进行聚合,聚合后的中间结果传给reduce函数,输入和reduce函数是一致的,被称为mapper端的reduce。了解了这个过程后,我们来看evaluator的几个方法,基本上是对应这几个阶段。


方法


作用


init


初始化函数


getNewAggregationBuffer


用来生成一个缓存对象,记录临时聚合结果


iterate


一条一条处理数据,将结果存入缓存


terminatePartial


这个方法意味着map阶段结束,将缓存中的数据持久化存储。这里返回的数据类型仅支持java基本类型、基本类型包装类、数组以及Hadoop的Writables, Lists和Map,不要使用自定义类型


merge


接收terminatePartial返回的结果,合并局部聚合结果


terminate


返回最终结果,可以在这里实现最后的求值,比如计算平均值

在hive中,用一个枚举类Mode来表示不同阶段

  /**
   * Mode.
   *官方的注释写的挺详细了^_^
   */
  public static enum Mode {
    /**
     * PARTIAL1: from original data to partial aggregation data: iterate() and
     * terminatePartial() will be called.
     */
    PARTIAL1,
        /**
     * PARTIAL2: from partial aggregation data to partial aggregation data:
     * merge() and terminatePartial() will be called.
     */
    PARTIAL2,
        /**
     * FINAL: from partial aggregation to full aggregation: merge() and
     * terminate() will be called.
     */
    FINAL,
        /**
     * COMPLETE: from original data directly to full aggregation: iterate() and
     * terminate() will be called.
     */
    COMPLETE
  };

嗯。。。 写完后打个jar包出来,创建个临时函数来使用既可以了

add jar hiveUDF.jar;
create temporary function test_udf as ‘com.test.xxxx‘;select test_udf(a,b) from table2 groupy by xxx.

好啦,先写这么多,我写的时候数据类型用的大部分是java的,所以产生了各种类型转换错误,后面打算看看Hadoop的内置类型~ 希望能帮到大家~

原文地址:https://www.cnblogs.com/jeason1991/p/10986716.html

时间: 2024-10-26 18:33:44

HIVE UDAF开发上手,你一看就懂!的相关文章

Hive UDAF开发详解

说明 这篇文章是来自Hadoop Hive UDAF Tutorial - Extending Hive with Aggregation Functions:的不严格翻译,因为翻译的文章示例写得比较通俗易懂,此外,我把自己对于Hive的UDAF理解穿插到文章里面. udfa是hive中用户自定义的聚集函数,hive内置UDAF函数包括有sum()与count(),UDAF实现有简单与通用两种方式,简单UDAF因为使用Java反射导致性能损失,而且有些特性不能使用,已经被弃用了:在这篇博文中我们

Hive自定义函数UDAF开发

Hive支持自定义函数,UDAF是接受多行,输出一行. 通常是group by时用到这种函数. 其实最好的学习资料就是官方自带的examples了. 我这里用的是0.10版本hive,所以对于的examples在 https://github.com/apache/hive/tree/branch-0.10/contrib/src/java/org/apache/hadoop/hive/contrib/udaf/example 我这里的功能需求是: actionCount(act_code,ac

干货!总结19个提升iOS开发技术的必看教程!

又到了ibnShawari一周一篇技术推送的时间了,今天我为大家带来了iOS开发篇,绝对实用,绝对简单!!! 注意!!本课程采用了一种系统且全面的方式学习:赶快来学习,体验这种方法的魔力吧!! 干货!总结19个提升iOS开发技术的必看教程!        本系列教程采用了最新的IOS开发技术进行讲解,视频中所有的例子都在最新的编译器中调试通过.理论上所有的例子都可以在成功运行.本路线图提供的视频课程是全网最深入,最全.通过对本路线图的学习,学员可以充分掌握IOS的开发过程,并具有一定的项目实战经

一看就懂的Android APP开发入门教程

一看就懂的Android APP开发入门教程 作者: 字体:[增加 减小] 类型:转载 这篇文章主要介绍了Android APP开发入门教程,从SDK下载.开发环境搭建.代码编写.APP打包等步骤一一讲解,非常简明的一个Android APP开发入门教程,需要的朋友可以参考下 工作中有做过手机App项目,前端和android或ios程序员配合完成整个项目的开发,开发过程中与ios程序配合基本没什么问题,而android各种机子和rom的问题很多,这也让我产生了学习android和ios程序开发的

Android开发华为手机无法看log日志解决方法

Android开发华为手机无法看log日志解决方法 上班的时候,由于开发工具由Eclipse改成Android Studio后,原本的华为手机突然无法查看崩溃日志了,大家都知道,若是无法查看日志要它毛用啊? 刚开始没想过是手机问题,毕竟在Eclipse中是完好了,结果在AS中华为了大量时间查找原因,最后,偶然换个手机发现别的手机正常... 最后百度发现解决方法: 进入拨号界面输入:*#*#2846579#*#* 依次选择[工程菜单 —> 后台设置 —> LOG设置 —> LOG开关]  

看得懂的 Node.js(三)—— Express 启航

如果看过上一篇<看得懂的 Node.js>,就会发现手动搭建一个 web 服务器还是比较繁琐 而 express 就是一个可以极大地提高开发效率的 web 开发框架 一.创建项目 在 express 4.0 之前,我们使用 npm install -g express 来全局安装 express 但是 4.0 之后,express 的命令行工具被单独分离出来,叫做 express-generator npm install -g express-generator 如果了解过 vue,expr

只有重庆人才看得懂的笑话!

一外省男,进重庆的饭店,点了个鱼香茄子,于是发生下面一段话 "老板,老板!!" "啥子事哦?" "你这鱼香茄子咋没得鱼呢?" "鱼香茄子本来就没得鱼嘛!" "没得鱼干嘛叫鱼香茄子呢?" "日你个先人板板-照你娃这么说,如果你要点个"虎皮青椒",老子还得给你弄张老虎皮不成?:点个"老婆饼",老子还给你发老婆不?:你P人点个"夫妻肺片",我不

ExtJs--14--Ext.typeOf() 与 javascript中的typeof很相似,只是在类型上进行了一点简单的扩展,其实可以直接看源代码就可以看得懂的

Ext.typeOf() // Ext.typeOf() 与 javascript中的typeof很相似,只是在类型上进行了一点简单的扩展,其实可以直接看源代码就可以看得懂的 // typeOf: function(value) { // var type, // typeToString; // // if (value === null) { // return 'null'; // } // // type = typeof value; // // if (type === 'undef

人人都看得懂的正则表达式

正则表达式可以帮助我们更好的描述复杂的文本格式.一旦你描述清楚了这些格式,那你就可以利用它们对文本数据进行检索.替换.提取和修改操作. 下面有一个正则表达式的简单例子.第一步先要引入有关正则式的命名空间: using System.Text.RegularExpressions; 第二步就是用指定的正则式构建一个正则表达式对象,下面的正则式是用来搜索长度为10的a-z的英文字母: Regex obj = new Regex("[a-z]{10}"); 最后,根据正则式在指定数据中检索匹