Hive中虽然自带了一些函数,例如max()、avg()、sum()等,但有时候这些函数可能无法满足我们的需要,这时候就可以通过自定义UDF来进行扩展。
开发流程
UDF的开发流程基本有以下步骤:
- 继承UDF类或者GenericUDF类;
- 重写evaluate()方法并实现函数逻辑;
- 打jar包;
- 上传到hdfs;
- 使用jar创建临时或者永久函数;
- 调用函数。
UDF实现
在重写之前,我们首先建立一个Maven工程。具体的方法大家可以参考我以前的一篇文章:
Hadoop的环境变量配置及与java的交互 创建完成后,需要下载两个包:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
注意版本要和自身的一致。
我们就来实现字母的全转大写这一方法:
1、建立一个Big类,继承UDF,编写evaluate方法:
如果文档值为空,则返回空值,如果有字母,则转为其大写输出,其他类型的数值则直接返回
public class Big extends UDF {
public Text evaluate(Text str) {
if (str == null) {
return null;
}
return new Text(str.toString().toUpperCase());
}
}
方法写好后打jar包先放到linux上去,再上传到hdfs。
我这里创建了一个文件路径:
hdfs dfs -mkdir -p /test/hive/functions
上传文件:
hdfs dfs -put UDFexercise.jar /test/hive/functions
临时函数
首先我们创建一个临时函数:
在Hive命令行使用 add jar jar包路径,把jar包加载到临时系统中
add jar /root/UDFexercise.jar;
然后实现这一函数:
create temporary function 函数名 as '方法的全路径’
create temporary function Big as 'Test.work.Big';
注意:此时如果报错可用以下方法解决。
下载zip包
yum install -y zip
删除META_INF包:
*zip -d jar包 ‘META-INF/.SF’ ‘META-INT/.RSA’ 'META-INF/SF’
zip -d UDFexercise.jar 'META-INF/.SF' 'META-INT/.RSA' 'META-INF/*SF';
然后退出hive再重新进入,再次执行以下步骤:
add jar /root/UDFexercise.jar;
create temporary function Big as 'Test.work.Big';
即可成功
我们可以直接通过select来实现这一方法:
select Big('abc');
永久函数
前面的步骤不变,当上传到hdfs后,我们选择需要用到的数据库。
use test;
创建永久函数的指令:
create function 函数名 as ‘方法的全路径’
using jar ‘hdfs:/主机名:9000/jar包的hdfs路径’;
create function Big as 'Test.work.Big' using jar 'hdfs://hadoop01:9000/test/hive/functions/UDFexercise.jar';
创建成功后,我们就可以永久调用此函数:
select Big('abc');
我们再举个例子。在一个时间的基础上,加上小时后得出新的时间。
public class Hour extends UDF {
public Text evaluate(Text times, IntWritable hours) throws ParseException {
//把接收到的数据转换成java类型
String str = times.toString();
int i = hours.get();
//日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//把字符串转换成Date类型
Date d = sdf.parse(str);
//计算时间,小时i*60分钟*60秒*1000毫秒得到新的时间,再把新的时间转成固定格式
String rst = sdf.format(new Date(d.getTime() + i * 60 * 60 * 1000));
return new Text(rst);
}
}
打成jar包上传后,根据上述方法建立临时/永久函数:
add jar /test/UDFexercise.jar;
create temporary function time as 'Test.work.Hour';
select time('2020-09-22 12:00:00',200);
临时UDF和永久UDF的区别
1、当我们创建一个临时UDF后,如果退出系统,那么这个函数也将消失,如果想要调用,需要登录上重新创建;而永久性的UDF函数则会一直存在;
2、临时UDF可以在任意库中直接调用,不受库限制;而永久性UDF函数在如果想要再其他库调用需要在函数名前加上库名。
例如,我在test库创建了一个永久性的Big函数,那么在其他库调用的时候需要这样写
select test.Big('abc');
才能执行成功。