博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Hive- UDF&GenericUDF
阅读量:4299 次
发布时间:2019-05-27

本文共 5917 字,大约阅读时间需要 19 分钟。

原文链接:

 

Hive- UDF&GenericUDF

 

hive udf简介

在Hive中,用户可以自定义一些函数,用于扩展HiveQL的功能,而这类函数叫做UDF(用户自定义函数)。UDF分为两大类:UDAF(用户自定义聚合函数)和UDTF(用户自定义表生成函数)。在介绍UDAF和UDTF实现之前,我们先在本章介绍简单点的UDF实现——UDF和GenericUDF,然后以此为基础在下一章介绍UDAF和UDTF的实现。

Hive有两个不同的接口编写UDF程序。一个是基础的UDF接口,一个是复杂的GenericUDF接口。

org.apache.hadoop.hive.ql. exec.UDF 基础UDF的函数读取和返回基本类型,即Hadoop和Hive的基本类型。如,Text、IntWritable、LongWritable、DoubleWritable等。

org.apache.hadoop.hive.ql.udf.generic.GenericUDF 复杂的GenericUDF可以处理Map、List、Set类型。

注解使用:

@Describtion注解是可选的,用于对函数进行说明,其中的FUNC字符串表示函数名,当使用DESCRIBE FUNCTION命令时,替换成函数名。@Describtion包含三个属性:

  • name:用于指定Hive中的函数名。
  • value:用于描述函数的参数。
  • extended:额外的说明,如,给出示例。当使用DESCRIBE FUNCTION EXTENDED name的时候打印。

而且,Hive要使用UDF,需要把Java文件编译、打包成jar文件,然后将jar文件加入到CLASSPATH中,最后使用CREATE FUNCTION语句定义这个Java类的函数:

  1. hive> ADD jar /root/experiment/hive/hive-0.0.1-SNAPSHOT.jar;
  2. hive> CREATE TEMPORARY FUNCTION hello AS "edu.wzm.hive. HelloUDF";
  3. hive> DROP TEMPORARY FUNCTION IF EXIST hello;

udf

简单的udf实现很简单,只需要继承udf,然后实现evaluate()方法就行了。evaluate()允许重载。

一个例子:

@Description(      name = "hello",      value = "_FUNC_(str) - from the input string"          + "returns the value that is \"Hello $str\" ",      extended = "Example:\n"          + " > SELECT _FUNC_(str) FROM src;"  )  public class HelloUDF extends UDF{            public String evaluate(String str){          try {              return "Hello " + str;          } catch (Exception e) {              // TODO: handle exception              e.printStackTrace();              return "ERROR";          }      }  }

genericUDF

GenericUDF实现比较复杂,需要先继承GenericUDF。这个API需要操作Object Inspectors,并且要对接收的参数类型和数量进行检查。GenericUDF需要实现以下三个方法:

//这个方法只调用一次,并且在evaluate()方法之前调用。该方法接受的参数是一个ObjectInspectors数组。该方法检查接受正确的参数类型和参数个数。  abstract ObjectInspector initialize(ObjectInspector[] arguments);    //这个方法类似UDF的evaluate()方法。它处理真实的参数,并返回最终结果。  abstract Object evaluate(GenericUDF.DeferredObject[] arguments);    //这个方法用于当实现的GenericUDF出错的时候,打印出提示信息。而提示信息就是你实现该方法最后返回的字符串。  abstract String getDisplayString(String[] children);

一个例子:判断array是否包含某个值。

/*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao (cnfree2000@hotmail.com) ***/package org.apache.hadoop.hive.ql.udf.generic;import org.apache.hadoop.hive.ql.exec.Description;import org.apache.hadoop.hive.ql.exec.UDFArgumentException;import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;import org.apache.hadoop.hive.ql.metadata.HiveException;import org.apache.hadoop.hive.serde2.objectinspector.ListObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils;import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;import org.apache.hadoop.io.BooleanWritable;@Description(name = "array_contains", value = "_FUNC_(array, value) - Returns TRUE if the array contains value.", extended = "Example:\n  > SELECT _FUNC_(array(1, 2, 3), 2) FROM src LIMIT 1;\n  true")public class GenericUDFArrayContains extends GenericUDF {    private static final int ARRAY_IDX = 0;    private static final int VALUE_IDX = 1;    private static final int ARG_COUNT = 2;    private static final String FUNC_NAME = "ARRAY_CONTAINS";    private transient ObjectInspector valueOI;    private transient ListObjectInspector arrayOI;    private transient ObjectInspector arrayElementOI;    private BooleanWritable result;    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {        if (arguments.length != 2) {            throw new UDFArgumentException("The function ARRAY_CONTAINS accepts 2 arguments.");        }        if (!(arguments[0].getCategory().equals(ObjectInspector.Category.LIST))) {            throw new UDFArgumentTypeException(0, "\"array\" expected at function ARRAY_CONTAINS, but \""                    + arguments[0].getTypeName() + "\" " + "is found");        }        this.arrayOI = ((ListObjectInspector) arguments[0]);        this.arrayElementOI = this.arrayOI.getListElementObjectInspector();        this.valueOI = arguments[1];        if (!(ObjectInspectorUtils.compareTypes(this.arrayElementOI, this.valueOI))) {            throw new UDFArgumentTypeException(1,                    "\"" + this.arrayElementOI.getTypeName() + "\"" + " expected at function ARRAY_CONTAINS, but "                            + "\"" + this.valueOI.getTypeName() + "\"" + " is found");        }        if (!(ObjectInspectorUtils.compareSupported(this.valueOI))) {            throw new UDFArgumentException("The function ARRAY_CONTAINS does not support comparison for \""                    + this.valueOI.getTypeName() + "\"" + " types");        }        this.result = new BooleanWritable(false);        return PrimitiveObjectInspectorFactory.writableBooleanObjectInspector;    }    public Object evaluate(GenericUDF.DeferredObject[] arguments) throws HiveException {        this.result.set(false);        Object array = arguments[0].get();        Object value = arguments[1].get();        int arrayLength = this.arrayOI.getListLength(array);        if ((value == null) || (arrayLength <= 0)) {            return this.result;        }        for (int i = 0; i < arrayLength; ++i) {            Object listElement = this.arrayOI.getListElement(array, i);            if ((listElement == null)                    || (ObjectInspectorUtils.compare(value, this.valueOI, listElement, this.arrayElementOI) != 0))                continue;            this.result.set(true);            break;        }        return this.result;    }    public String getDisplayString(String[] children) {        assert (children.length == 2);        return "array_contains(" + children[0] + ", " + children[1] + ")";    }}

总结

当写Hive UDF时,有两个选择:一是继承 UDF类,二是继承抽象类GenericUDF。这两种实现不同之处是:GenericUDF 可以处理复杂类型参数,并且继承GenericUDF更加有效率,因为UDF class 需要HIve使用反射的方式去实现。

UDF是作用于一行的。

转载地址:http://ekvws.baihongyu.com/

你可能感兴趣的文章
Vue 路由懒加载根据根路由合并chunk块
查看>>
vue中 不更新视图 四种解决方法
查看>>
MySQL 查看执行计划
查看>>
OpenGL ES 3.0(四)图元、VBO、VAO
查看>>
OpenGL ES 3.0(五)纹理
查看>>
OpenGL ES 3.0(八)实现带水印的相机预览功能
查看>>
OpenGL ES 3.0(九)实现美颜相机功能
查看>>
FFmpeg 的介绍与使用
查看>>
Android 虚拟机简单介绍——ART、Dalvik、启动流程分析
查看>>
原理性地理解 Java 泛型中的 extends、super 及 Kotlin 的协变、逆变
查看>>
FFmpeg 是如何实现多态的?
查看>>
FFmpeg 源码分析 - avcodec_send_packet 和 avcodec_receive_frame
查看>>
FFmpeg 新旧版本编码 API 的区别
查看>>
RecyclerView 源码深入解析——绘制流程、缓存机制、动画等
查看>>
Android 面试题整理总结(一)Java 基础
查看>>
Android 面试题整理总结(二)Java 集合
查看>>
学习笔记_vnpy实战培训day02
查看>>
学习笔记_vnpy实战培训day03
查看>>
VNPY- VnTrader基本使用
查看>>
VNPY - CTA策略模块策略开发
查看>>