Hive UDF的编写


=Start=

缘由:

有时候Hive提供的官方函数不能/很难满足业务需求,这时我们可以采用Hive提供的更加灵活的解决方案:UDF(User Defined Function, 用户自定义函数)。在这里简单整理一下Hive中编写UDF的方法,方便以后需要的时候参考。

正文:

参考解答:
常见的3种 Hive 自定义函数

(1) UDF(user-defined function) 一进一出,给定一个输入,输出一个处理后的数据。许多Hive内置字符串,数学函数,时间函数都是这种类型。大多数情况下编写对应功能的处理函数就能满足需求。如:concat, split, length ,rand等。这种UDF主要有两种写法:继承实现 UDF类 和 继承GenericUDF类(通用UDF)。

(2) UDAF(user-defined aggregate function) 多进一出,属于聚合函数,类似于count、sum等函数。一般配合group by使用。主要用于累加操作,常见的函数有max, min, count, sum, collect_set等。这种UDF主要有两种写法:继承实现 UDAF类 和 继承实现 AbstractGenericUDAFResolver类 。

(3) UDTF(user-defined table function) 一进多出,将输入的一行数据产生多行数据或者将一列打成多列。如explode函数通常配合lateral view使用,实现列转行的功能。parse_url_tuple将一列转为多列。

在决定编写自己的函数之前,可以先看看Hive中已经有了哪些函数及其功能:

show functions; --查看已有函数
describe function concat; --查看函数用法
describe function extended concat; --查看函数的用法和示例

通用UDF的编写示例及说明

通用UDF的实现很简单,只需要继承UDF,然后实现evaluate()方法就行了。

import org.apache.commons.lang.StringUtils; //引用的其它字符串处理函数

import org.apache.hadoop.hive.ql.exec.UDF; //需要继承的类
import org.apache.hadoop.io.Text; //Hadoop的Text类型表示文本

public class Strip extends UDF {
    private Text result = new Text();

    public Text evaluate(Text str) {
        if (str == null) {
            return null;
        }
        result.set(StringUtils.strip(str.toString()));
        return result;
    }

    public Text evaluate(Text str, String stripChars) {
        if (str == null) {
            return null;
        }
        result.set(StringUtils.strip(str.toString(), stripChars));
        return result;
    }
}

要点就 2 个:
(1) 继承类 org.apache.hadoop.hive.ql.exec.UDF ;
(2) 至少实现一个 evaluate() 方法, evaluate 方法可以使用不同个数和类型的参数。

evaluate()方法支持的类型如下:

public int evaluate();
public int evaluate(int a);
public double evaluate(int a, double b);
public String evaluate(String a, int b, Text c);
public Text evaluate(String a);
public String evaluate(List a);
public List evaluate(List a);
public Map<Integer, String> evaluate(Map<Integer,String> a);

编写、测试好了之后打成一个jar包,然后上传使用即可,具体的根据各自搭建的环境对应手册操作即可。

自定义函数的调用过程(添加、创建、调用)
  • ①添加 jar 包(在Hive命令行里面执行)

hive> add jar /path/to/StripUDF.jar;

  • ②创建临时函数

hive> create temporary function strip as 'com.ixyzero.hive.udf.StripUDF';

临时函数的缺点是在下次启动Hive集群时自动失效(可以每次在用的时候都先add再create)。当然,我们也可以直接创建永久函数,这样就不用担心失效的问题了,问题在于创建过程比较复杂,需要修改源码。

  • ③调用

hive> select strip(' space will be strip ') as result;

参考链接:

HIVE UDF函数编写
https://github.com/delongwu/techdoc/wiki/HIVE-UDF%E5%87%BD%E6%95%B0%E7%BC%96%E5%86%99

Hive UDF教程(一)
https://blog.csdn.net/u010376788/article/details/50532166
Hive UDF教程(二)
https://blog.csdn.net/u010376788/article/details/50537984
Hive UDF教程(三)
https://blog.csdn.net/u010376788/article/details/50540633

官方文档
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
https://cwiki.apache.org/confluence/display/Hive/HivePlugins

https://blog.matthewrathbone.com/2013/08/10/guide-to-writing-hive-udfs.html

https://snowplowanalytics.com/blog/2013/02/08/writing-hive-udfs-and-serdes/

https://dzone.com/articles/writing-custom-hive-udf-andudaf

Hive简易教程 – 自定义UDF
https://www.jianshu.com/p/7f8329443aae

Hive入门–3.UDF编写与使用
https://blog.csdn.net/u014726937/article/details/51985177

hive udf开发超详细手把手教程
https://blog.csdn.net/bitcarmanlee/article/details/51249260

Hive添加自定义UDF函数
https://liam-blog.ml/2016/04/11/add-udf-to-hive/

Hive基础之UDF编程
https://zhuanlan.zhihu.com/p/58072588

=END=

,

《 “Hive UDF的编写” 》 有 11 条评论

  1. Working with Hive Macros, Syntax and Examples
    https://dwgeek.com/working-with-hive-macros-syntax-and-examples.html/

    https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-Create/DropMacro

    HIVE中MACRO(宏)的使用
    https://blog.csdn.net/weixin_39454683/article/details/90485257
    `
    在编写HQL的过程中,很多逻辑需要反复使用。这时我们可以使用宏对这段逻辑进行提炼,起到优化开发效率、提升程序可读性的效果(尤其是括号嵌套很多层、case-when嵌套很多层的时候)。举个例子:

    create temporary macro sayhello (x string) concat(‘hello,’,x,’!’);
    select sayhello(‘程序员’); –输出:hello,程序员!

    在上面的的代码中,首先我们定义了一个名为sayhello的宏,输入参数为一个字符串x,输出为对x的拼接。如果之后还需要向HR问好,只要输入sayhello(‘HR’)即可。

    显而易见,我们可以把宏当做一个自定义“函数”,其开发过程与UDF相比更加简捷。
    `

  2. hive利器 宏macro的详解
    https://blog.csdn.net/shuimofengyang/article/details/97112753
    `
    一、有关空值的处理
    1. 空串转NULL
    2. NULL转空串
    3. 判断NULL和空串

    二、有关时间的计算
    1. 上个月第一天
    2. 上个月最后一天
    3. 时间差
    4. 日期处理
    5. 时间比较

    三、数学计算
    1. 按0.5向上取整
    `
    Hive中常被忽视的利器——宏
    https://segmentfault.com/a/1190000009816609
    `
    大多数情况下我们并不是真正需要(不得不用)UDF,大多数时候我们仅仅只是需要把一些虽然繁琐但其实结构简单的逻辑封装起来以便重复使用。
    其实【大多数不需要循环结构的逻辑,基本上都可以用宏来处理】。它不仅可以用来做字段值的转换映射,也可以做逻辑校验。
    比如:根据生日推算星座、判断身份证号是否合法
    `

    Hive笔记之宏(macro)
    https://www.cnblogs.com/cc11001100/p/10232531.html
    `
    宏可以看做是一个简短的函数,或者是对一个表达式取别名,同时可以将这个表达式中的一些值做成变量调用时传入,比较适合于做分析时为一些临时需要用到很多次的表达式操作封装一下取个简短点的别名来调用。宏只在当前会话有效,当退出hive控制台再进入时上次创建的宏就丢失了,如果需要永久保留某个宏,可以将其加入到${HIVE_HOME}/.hiverc文件中。
    `

  3. UDFArrayJoin.java
    https://github.com/dataiku/dataiku-hive-udf/blob/master/src/com/dataiku/hive/udf/arrays/UDFArrayJoin.java

    Hive UDF Text to array
    https://stackoverflow.com/questions/17137194/hive-udf-text-to-array
    `
    Actually the ‘UDF’ interface does support returning an array.

    Return ArrayList or even ArrayList instead of Text[]
    `

    A Complete Guide to Writing Hive UDF
    https://blog.dataiku.com/2013/05/01/a-complete-guide-to-writing-hive-udf
    `
    除非你要写的UDF是返回 struct 类型(或者接收的内容是复杂类型),否则一般情况下使用 UDF 就行,不需要 GenericUDF
    `

    UDAF mean example
    https://riptutorial.com/hive/example/18155/udaf-mean-example

    hive UDF自定义函数 map处理
    https://blog.csdn.net/qq_26645205/article/details/78498995

  4. Re: slow performance when using udf
    https://lists.apache.org/thread/8nmhz8kwmmxf0jzpsjr2f2bnzsyfwqtm
    `
    Finally, the flowing code get no performance lose. I think the point is to avoid to use the getString method, Thanks everyone again.

    简单来说就是,如果你想实际测试/验证你写的UDF对性能损耗是不是很大,可以先用一个基本没什么特殊功能的UDF做一个基准,然后再对比加上其它逻辑的UDF之后的查询耗时有没有明显增加。
    `

    Using Hive Advanced User Defined Functions with Generic and Complex Data Types
    https://www.bmc.com/blogs/using-hive-advanced-user-defined-functions-with-generic-and-complex-data-types/
    `
    Programs that extend org.apache.hadoop.hive.ql.exec.UDF are for primitive data types, i.e., int, string. Etc. If you want to process complex types you need to use org.apache.hadoop.hive.ql.udf.generic.GenericUDF. Complex types are array, map, struct, and uniontype.

    Generic functions extend org.apache.hadoop.hive.ql.udf.generic.GenericUDF and implement the 3 interfaces shown below.

    class MapUpper extends GenericUDF {
    override def initialize(args: Array[ObjectInspector]): ObjectInspector = {}
    override def getDisplayString(arg0: Array[String] ) : String = { return “silly me”; }
    override def evaluate(args: Array[DeferredObject]): Object = {}
    }

    This is the same as the simple UDF code, except there are two additional functions: initialize and getDisplay. Those set up an ObjectInspector and display a message if there is an error.

    initialize looks at the value passed from Hive SQL to the function. There you check the argument count and type. Then it determines the type of argument that was passed to it. Then the evaluate function uses that typeless-argument, which is contained in org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredObject.

    As you can see from the Scala code above, that returns an object of type Object, meaning there is no type definition and no ability for the compiler to find errors (Thus will show up at runtime.).

    The initialize function returns the type of argument expected by the evaluate function.
    `

    How to write a Hive UDF
    http://mark.thegrovers.ca/tech-blog/how-to-write-a-hive-udf
    `
    UDF
    开发起来比较简单,只需要继承UDF,然后实现evaluate()方法就行。 Easier to develop
    因为使用了反射,所以性能比较低。 Lower performance due to use of reflection
    不支持一些非基本类型的参数。 Doesn’t accept some non-primitive parameters like struct

    GenericUDF
    开发起来会复杂一点,相比UDF多了2个要实现的方法:initialize 和 getDisplayString,它们设置了一个 ObjectInspector 并当错误发生时会展示一些信息。 A little more difficult to develop
    性能比UDF更好,因为使用延迟和短路执行。 Better performance because use of lazy evaluation and short-circuiting
    支持所有非原语参数作为输入参数和返回类型。 Supports all non-primitive parameters as input parameters and return types
    `

    GenericUDFTranslate.java
    https://github.com/apache/hive/blob/master/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFTranslate.java

    GenericUDFStringToMap.java
    https://github.com/apache/hive/blob/master/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFStringToMap.java

  5. Hive UDF 简介
    https://www.hadoopdoc.com/hive/hive-udf-intro
    `
    在 Hive 中,用户可以自定义一些函数,用于扩展 HiveQL 的功能,而这类函数叫做 UDF,也就是用户自定义函数。UDF 分为两大类:UDAF(用户自定义聚合函数)和 UDTF(用户自定义表生成函数)。本节介绍的是比较简单的 UDF 实现—— UDF 和 GenericUDF。

    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 类型。

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

    abstract ObjectInspector initialize(ObjectInspector[] arguments);
    这个方法只调用一次,并且在evaluate()方法之前调用。该方法接受的参数是一个 ObjectInspectors 数组。该方法检查接受正确的参数类型和参数个数。

    abstract Object evaluate(GenericUDF.DeferredObject[] arguments);
    这个方法类似 UDF 的 evaluate() 方法。它处理真实的参数,并返回最终结果。

    abstract String getDisplayString(String[] children);
    这个方法用于当实现的 GenericUDF 出错的时候,打印出提示信息。而提示信息就是你实现该方法最后返回的字符串。
    `

  6. Class GenericUDF
    https://docs.cloudera.com/HDPDocuments/HDP2/HDP-2.1.2/hive_javadocs/ql/org/apache/hadoop/hive/ql/udf/generic/GenericUDF.html
    `
    abstract ObjectInspector initialize(ObjectInspector[] arguments)
    # Initialize this GenericUDF. This will be called once and only once per GenericUDF instance.

    abstract Object evaluate(GenericUDF.DeferredObject[] arguments)
    # Evaluate the GenericUDF with the arguments.

    abstract String getDisplayString(String[] children)
    # Get the String to be displayed in explain.
    `

    GenericUDFInstr.java
    https://github.com/apache/hive/blob/master/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFInstr.java

    Hive之ObjectInspector详解
    https://blog.csdn.net/weixin_42167895/article/details/108314139

    DeveloperGuide
    https://cwiki.apache.org/confluence/display/hive/developerguide#DeveloperGuide-UDFsandUDAFs-howtoaddnewUDFsandUDAFs

回复 hi 取消回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注