Hive——用户自定义函数(UDF)

来源:互联网 发布:思科网络技术学院4本书 编辑:程序博客网 时间:2024/05/21 22:21

Hive——用户自定义函数(UDF)

  用户自定义函数(UDF)是一个允许用户扩展HiveQL的强大的功能。用户可以使用Java编写自己的UDF,一旦将用户自定义函数加入到用户会话中(交互式的或者通过脚本执行的),它们就将和内置的函数一样使用,甚至可以提供联机帮助。Hive具有多种类型的用户自定义函数,每一种都会针对输入数据执行特定“一类”的转换过程。

  在ETL处理中,一个处理过程可能包含多个处理步骤。Hive语言具有多种方式来将上一步骤的输入通过管道传递给下一个步骤,然后在一个查询中产生众多输出。用户同样可以针对一些特定的处理过程编写自定义函数。如果没有这个功能,那么一个处理过程可能就需要包含一个MapReduce步骤或者需要将数据转移到另一个系统中来实现这些改变。因此,Hive提供了用户自定义函数(UDF),UDF是在Hive查询产生的相同的task进程中执行的,因此它们可以高效地执行。


发现和描述函数

  在编写自定义UDF之前,我们先来熟悉下Hive中自带的那些UDF。需要注意的是在Hive中通常使用“UDF”来表示任意的函数,包括用户自定义的或者内置的。

  SHOW FUNCTIONS命令可以列举出当前Hive会话中所加载的所有函数名称,其中包括内置的和用户加载进来的函数。

  函数通常都有其自身的使用文档。使用DESCRIBE FUNCTION 命令可以展示对应函数简短的介绍。(如:DESCRIBE FUNCTION concat;)

  函数也可能包含更多的详细文档,可以通过DESCRIBE FUNCTION EXTENDED 命令进行查看。(如:DESCRIBE FUNCTION EXTENDED concat;)


调用函数

  如果想使用函数,只需要在查询中通过调用函数名,并传入需要的参数即可。某些函数需要指定特定的参数个数和参数类型,而其他函数可以传入一组参数,参数类型可以是多样的。和关键字一样,函数名也是保留的字符串:

SELECT concat(column1, column2) AS x FROM table;

编写UDF

  编写一个UDF,需要继承UDF并实现evaluate()函数。在查询过程中,查询中对应的每个应用到这个函数的地方都会对这个类进行实例化。对于每行输入都会调用evaluate()函数。而evaluate()处理后的值会返回给Hive。同时用户是可以重载evaluate方法的。Hive会像Java的方法重载一样,自动选择匹配的方法。

package com.test.hive.udf;import java.text.SimpleDateFormat;import java.util.Date;import org.apache.hadoop.hive.ql.exec.Description;import org.apache.hadoop.hive.ql.exec.UDF;@Description(name = "deprecation",        value = "_FUNC_(date, price) - from the input date string(yyyyMMdd), " +                 "returns the deprecation price by computing price and "                + "the depreciation rate of the second-hand car.",        extended = "Example:\n" +                    " > SELECT _FUNC_(date_string, price) FROM src;")public class TestUDF extends UDF {    private SimpleDateFormat df;    private double[] rates;    public TestUDF() {        df = new SimpleDateFormat("yyyyMMdd");        rates = new double[]{0.071, 0.070, 0.069, 0.067, 0.064,                            0.062, 0.060, 0.057, 0.055, 0.053,                            0.051, 0.049, 0.049, 0.048, 0.046,                            0.044};    }    @SuppressWarnings("deprecation")    public String evaluate(String deal_date, String price) {        Date date = null;        Date now = new Date();//获取当前时间        long price_ = Long.valueOf(price);        try {            date = df.parse(deal_date);            /*37-45行是固定的算法,可以替换自己的算法*/            double numMonth = (now.getYear() * 12 + now.getMonth())                    - (date.getYear() * 12 + now.getMonth()) + 1;            double mileage = ((6.000 - (1.7000 * numMonth / 12)) / 1.7000) * 12 * 0.25;            double total = numMonth + mileage;            int depre_year = (int) (total / 12);            for(int i = 0; i < depre_year + 1; i++) {                price_ = (long) (price_ * (1 - rates[i]));            }        } catch(Exception ex) {            return null;        }        return Long.toString(price_);    }}

  代码中的@Description(…)表示的是Java总的注解,是可选的。注解中注明了关于这个函数的文档说明,用户需要通过这个注解来阐明自定义的UDF的使用方法和例子。这样当用户通过DESCRIBE FUNCTION …命令查看该函数时,注解中的_FUNC_字符串将会被替换为用户为为这个函数定义的“临时”函数名称,定义方式下面会进行介绍。

提示:UDF中的evaluate()函数的参数和返回值类型只能是Hive可以序列化的数据类型。例如,如果用户处理的全是数值,那么UDF的输出参数类型可以是基本数据类型int、Integer封装的对象或者是一个IntWritable对象,也就是Hadoop对整型封装后的对象。用户不需要特别地关心将调用到哪个类型,因为当类型不一致时,Hive会自动将类型转换成匹配的类型。需要记住的是,null在Hive中对于任何数据类型都是合法的,但是对于Java基本数据类型,不能是对象,也不能是null。

  如果想在Hive中使用UDF,那么需要将Java代码进行编译,然后将编译后的UDF二进制类文件打包成一个JAR文件。如下步骤:

  1. 右键项目,选择Export;
  2. 选择导出格式为JAR file格式:
    这里写图片描述
  3. 点击Next,选择要导出的项目,以及填写导出的目录:
    这里写图片描述
  4. 点击Finish完成。

  然后,在Hive会话中,将这JAR文件加入到类路径下,再通过CREATE FUNCTION语句定义好使用这个Java类的函数:

hive> ADD JAR /home/hadoop/deprecation.jar;Added [/home/hadoop/deprecation.jar] to class pathAdded resources: [/home/hadoop/deprecation.jar]hive> CREATE TEMPORARY FUNCTION deprecation AS 'com.test.hive.udf.TestUDF';OKTime taken: 0.7 seconds

  需要注意的是,JAR文件路径是不需要用引号括起来的,同时,到目前为止这个路径需要是当前文件系统的全路经。Hive不仅仅将这个JAR文件加入到classpath下,同时还将其加入到分布式缓存中,这样整个集群的机器都是可以获得该JAR文件的。

  需要注意的是,CREATE FUNCTION语句中的TEMPORARY这个关键字。当前会话中声明的函数只会在当前会话中有效。因此用户需要在每个会话中都增加JAR然后创建函数。不过,如果用户需要频繁地使用同一个JAR文件和函数的话,那么可以将相关语句增加到$HOME/.hiverc文件中去。

  下面是应用示例:

hive> DESCRIBE FUNCTION deprecation;OKdeprecation(date, price) - from the input date string(yyyyMMdd), returns the deprecation price by computing price and the depreciation rate of the second-hand car.Time taken: 0.403 seconds, Fetched: 1 row(s)hive> DESCRIBE FUNCTION EXTENDED deprecation;OKdeprecation(date, price) - from the input date string(yyyyMMdd), returns the deprecation price by computing price and the depreciation rate of the second-hand car.Example: > SELECT deprecation(date_string, price) FROM src;Time taken: 0.008 seconds, Fetched: 3 row(s)hive> SELECT deal_date, substring(total_price, 0, 2), deprecation(deal_date, substring(total_price, 0, 2)) FROM stg_price;OK20150513    13  1120150514    13  11Time taken: 0.057 seconds, Fetched: 2 row(s)

  再次说明下,UDF允许用户在Hive语言中执行自定义的转换过程。通过上面那个UDF,Hive现在可以执行对二手车的简单折旧计算。

  当我们使用完自定义UDF后,我们可以通过如下命令删除此函数:

hive> DROP TEMPORARY FUNCTION IF EXISTS deprecation;OKTime taken: 0.066 seconds

  像通常一样,IF EXISTS是可选的。如果增加此关键字,则即使函数不存在也不会报错。

0 0
原创粉丝点击