一、简介
Hive有三种类型的UDF:(普通)UDF、用户定义聚集函数(user-defined aggregate function,UDAF)以及用户定义表生成函数(user-defined table-generating function,UDTF)。
- UDF:操作作用于单个数据行,且产生一个数据行作为输出。大多数函数(例如数学函数和字符串函数)都属于这一类。
- UDAF:接受多个输入数据行,并产生一个输出数据行。比如,COUNT和MAX函数。
- UDTF:作用于单个数据行,且产生多个数据行(即一个表)作为输出。比如,alteral view与explode函数。
二、编写UDF
在开发 Hive UDF 之前,我们需要引入一个 jar包:hive-exec。
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>
默认的scope是compile,表示项目在编译,测试,运行阶段都需要这个jar包在classpath中。这里指定scope为provided,表示仅在编译,测试阶段需要这个Jar包。因为在运行时,hive已经有该Jar包了,不需要重复依赖。
接着,我们需要实现UDF接口。目前 Hive 的 UDF 主要分为2种类型的接口:UDF和GenericUDF。
- UDF:是一种比较简单的类,继承的基类为 org.apache.hadoop.hive.ql.exec.UDF
- GenericUDF:相对复杂一些,主要针对于类型检查等具有更好的控制。继承的基类为 org.apache.hadoop.hive.ql.udf.generic.GenericUDF。
下面,我们看一个简单的UDF实现类:Strip
package com.scb.dss.udf;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
@Description(name = "strip",
value = "_FUNC_(str) - Removes the leading and trailing space characters from str.")
public class Strip extends UDF {
// 去除str开头以及结尾的空格
public String evaluate(String str) {
if (str == null) {
return null;
}
return StringUtils.strip(str);
}
// 去除str开头以及结尾的stripChars中该指定字符集中的任意字符
public String evaluate(String str, String stripChars) {
if (str == null) {
return null;
}
return StringUtils.strip(str, stripChars);
}
}
这个Strip类有两个evaluate方法。第一个方法会去除str开头以及结尾的空格,而第二个方法会去除str开头以及结尾的stripChars中该指定字符集中的任意字符。
@Description 注解注明了关于该UDF函数的文档说明,后续可通过desc function <UDF> 命令查看。该注解有三个属性:name,value,extended。
- name:表明了该函数的名称
- value:描述了该函数的作用,其中_FUNC_是个宏定义,在desc时候会被替换为这个函数的实际名称
- extended:主要用来编写函数使用示例
其他需要注意的点:
- UDF名称对大小写不敏感
- Hive支持在UDF中使用Java的基本数据类型(以及java.util.map和java.util.list这样的类型)。
- Hive也支持Hadoop基本数据类型,比如Text。推荐使用Hadoop基本数据类型,这样可以利用对象重用的优势,增效节支。
下面,做个简单UT
package com.scb.dss.udf;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.*;
public class StripTest {
private Strip strip = new Strip();
@Test
public void evaluate() {
System.out.println(strip.evaluate(" a b c "));
Assert.assertEquals("a b c", strip.evaluate(" a b c "));
System.out.println(strip.evaluate(" a b c a", "a"));
Assert.assertEquals(" a b c ", strip.evaluate(" a b c a", "a"));
System.out.println(strip.evaluate(" a b c a", "a "));
Assert.assertEquals("b c", strip.evaluate(" a b c a", "a "));
}
}
三、部署UDF
1. 打包
mvn clean package
2. 上传Jar包到HDFS
hdfs dfs -put hive-udf.jar /user/hive/
3. 通过beeline连接HIVE
beeline -u jdbc:hive2://host:10000/default -n username -p 'password'
4. 创建函数
create function strip as 'com.scb.dss.udf.UDFStrip' using jar 'hdfs:///user/hive/hive-udf.jar';
5. 使用
通过desc function <UDF> 查看UDF描述信息。
select strip('0a0', '0'); // 去除首位的0
四、其他
- 删除函数:drop function <udf>
- 创建临时函数:create temporary function <udf> as <udf.class.path>