当 Hive 提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
根据用户自定义函数类别分为以下三种:
UDF(User-Defined-Function)一进一出。
UDAF(User-Defined Aggregation Function)用户自定义聚合函数,多进一出。
UDTF(User-Defined Table-Generating Functions)用户自定义表生成函数,一进多出。
聚合函数 UDAF 能够满足我们使用的基本都已经内置了,本文就重点介绍一下UDF和UDTF函数的实现。
一、定义要求
1. 继承Hive提供的类
org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
2. 实现类中的抽象方法
UDF函数类
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
}
public Object evaluate(DeferredObject[] arguments) throws HiveException {
}
public String getDisplayString(String[] children) {
}
UDTF函数类
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
}
public void process(Object[] args) throws HiveException {
}
public void close() throws HiveException {
}
3. 在Hive的命令行窗口创建函数
① 添加打包上传的jar包。
add jar linux_jar_path
② 创建Funcation。
create [temporary] function [dbname.]function_name AS class_name;
③ 删除函数
drop [temporary] function [if exists】[dbname.]function_name;
二、实现UDF函数
自定义一个UDF实现计算给定基本数据类型的长度,例如:
select my_len(“abcd”);4
1. 创建Maven工程,导入依赖
<dependencies><dependency><groupId>org.apache.hive</groupId>、
<artifactId>hive-exec</artifactId>
<version>3.1.3</version>
</dependency></dependencies>
2. 创建函数类实现GenericUDF类
package com.atguigu;
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.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
public class LengthUDFTest extends GenericUDF {
//initialize方法,全局执行一次(一般做一些校验)
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 判断输入参数的个数
if (arguments.length != 1) {
throw new UDFArgumentException(“输入参数长度异常,只允许输入1个参数”);
}
// 判断输入参数的类型(是否是基本类型)
// Category 共定义了5种类型:基本类型(Primitive),集合(List),键值对映射(Map),结构体(Struct),联合体(Union)
if(!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
throw new UDFArgumentTypeException(0,”输入参数类型异常”);
}
// 函数本身返回值为 int,需要返回 int 类型的鉴别器对象
return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
}
//evaluate方法,函数的逻辑处理方法,进来一条执行一次
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
if (arguments[0].get() == null) {
return 0;
} else {
return arguments[0].get().toString().length();
}
}
//getDisplayString 方法,在使用explain 查看SQL执行计划时,会显示(一般直接返回null即可)
@Override
public String getDisplayString(String[] strings) {
return null;
}
}
三、实现UDTF函数
自定义UDTF函数实现按照分隔符切割字符串,变成多个单词。
1. 创建Mvaen工程,导入依赖
2. 创建函数类实现GenericUDTF类
package com.atguigu;
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.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
public class SplitUDTFTest extends GenericUDF {
//initialize方法,全局执行一次(一般做一些校验)
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 判断输入参数的个数
if (arguments.length != 1) {
throw new UDFArgumentException(“输入参数长度异常,只允许输入1个参数”);
}
// 判断输入参数的类型(是否是基本类型)
// Category 共定义了5种类型:基本类型(Primitive),集合(List),键值对映射(Map),结构体(Struct),联合体(Union)
if(!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
throw new UDFArgumentTypeException(0,”输入参数类型异常”);
}
// 函数本身返回值为 int,需要返回 int 类型的鉴别器对象
return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
}
//evaluate方法,函数的逻辑处理方法,进来一条执行一次
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
if (arguments[0].get() == null) {
return 0;
} else {
return arguments[0].get().toString().length();
}
}
//getDisplayString 方法,在使用explain 查看SQL执行计划时,会显示(一般直接返回null即可)
@Override
public String getDisplayString(String[] strings) {
return null;
}
}
四、自定义函数的使用
UDF函数和UDTF函数的使用一样,测试一下自定义的UDF。
1. 临时函数
①打成jar包上传到服务器/hive/datas/myudf.jar。
②将jar包添加到hive的classpath,临时生效。
add jar /hive/datas/myudf.jar;
③创建临时函数与开发好的java class关联。
create temporary function my_len as “com.atguigu.LengthUDFTest”;
④即可在hql中使用自定义的临时函数
select ename, my_len(ename) ename_lenfrom emp;
⑤删除临时函数
drop temporary function my_len;
注意:
临时函数只跟会话有关系,跟库没有关系。只要创建临时函数的会话不断,在当前会话下,任意一个库都可以使用,其他会话全都不能使用。
2. 永久函数
①创建永久函数
注意:
因为add jar本身也是临时生效,所以在创建永久函数的时候,需要制定路径(并且因为元数据的原因,这个路径还得是HDFS上的路径)。
create function my_len2 as “hive.udf.MyUDF” using jar “hdfs://hadoop:8020/udf/myudf.jar”;
②即可在hql中使用自定义的永久函数。
select ename, my_len2(ename) ename_lenfrom emp;
③删除永久函数。
drop function my_len2;
注意:
永久函数跟会话没有关系,创建函数的会话断了以后,其他会话也可以使用。
永久函数创建的时候,在函数名之前需要自己加上库名,如果不指定库名的话,会默认把当前库的库名给加上。
永久函数使用的时候,需要在指定的库里面操作,或者在其他库里面使用的话加上,库名.函数名。
五、总结
本文讲解了HIVE的自定义函数的实现步骤,实现了一个简单的计算给定基本数据类型的长度的UDF函数,其余的两种函数自定义需要大家去操作体验。