ToB企服应用市场:ToB评测及商务社交产业平台
标题:
Hive自定义函数编写方法(含源代码解读,超详细,易理解)
[打印本页]
作者:
数据人与超自然意识
时间:
2024-8-17 03:02
标题:
Hive自定义函数编写方法(含源代码解读,超详细,易理解)
一、Hive自定义函数介绍
1
.内置函数
Hive 自带了一些函数。好比:max/min等,但是数目有限,自己可以通过自定义函数来方便的扩展。
2
.自定义函数
当Hive提供的内置函数无法满足你的业务处置惩罚需要时,此时就可以思量使用用户自定义函数(UDF:user-defined function)。
3
.
用户自定义函数类别
用户自定义函数根据输入参数和输出效果的个数分为以下三类:
①
UDF
(User-Defined-Function)
一进一出
②
UDAF
(User-Defined Aggregation Function)
聚合函数
,
多进一出
,如:count/max/min
③
UDTF
(User-Defined Table-Generating Functions)
炸裂函数
,
一进多出
,如:explode()
4
.
官方文档地址
HivePlugins - Apache Hive - Apache Software Foundation
https://cwiki.apache.org/confluence/display/Hive/HivePlugins
5
.
编程实现步骤
① 继承Hive提供的类:
org.apache.hadoop.hive.ql.udf.generic.GenericUDF
·org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
② 实现类中的抽象方法
③ 在hive的命令行窗口创建函数
二、详细实现
为了能够更好地演示过程,本文以编写一个判断字符串长度的函数为例,函数定名为mystrlen(),详细实现效果如下图所示。
1.准备工作
① 创建一个Maven工程Hive
② 在工程项目的pom.xml文件中导入依靠,详细代码如下。本文选用的是Hive3.1.2版本,各人可以根据自己的版本自行更改。
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
复制代码
2.继承Hive提供的类
经太过析不难发现,该函数应该以一个字符串为输入参数,终极输出一个int型的整数以表明该字符串的长度。其对应的自定义函数类别是UDF(一进一出)类型。所以我们应该继承前文所提到的GenericUDF类。
创建my_strlen类以继承GenericUDF类。由于GenericUDF类为抽象类,所以在继承后,我们必须实现其抽象方法,如下图所示。我们的主要任务便是对前两个函数进行重写。
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
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;
/**
* 自定义UDF函数,需要继承GenericUDF类
* 需求: 计算指定字符串的长度
*/
public class my_strlen extends GenericUDF {
/**
*
* @param arguments 输入参数类型的鉴别器对象
* @return 返回值类型的鉴别器对象
* @throws UDFArgumentException
*/
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
return null;
}
/**
* 函数的逻辑处理
* @param arguments 输入的参数
* @return 返回值
* @throws HiveException
*/
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
return null;
}
@Override
public String getDisplayString(String[] children) {
return null;
}
}
复制代码
看到上述idea自动天生的代码,可能各人有点慌了。ObjectInspector是什么?DeferredObject又是什么?这些函数详细是做啥的?让我们一步一步的来。
在这里,
第一个方法initialize()的作用为对自定义函数进行初始化
。详细需要我们实现的有:查验函数的参数个数和参数类型是否正确,而且返回函数返回值类型的ObjectInspector。
对于第二个方法evaluate,我们需要实现函数的详细功能,而且返回函数终极的输出效果
。两个方法的形参都是argument,顾名思义,此形参传递的便是函数的参数信息。
对于不熟悉的类,我们首先应该去翻译其类名,然后分析其源码。ObjectInspector,顾名思义,该类应该是一个辨别器,详细辨别什么就需要我们对源码进行分析。让我们看下列源码,不难发现一些关键词 :gettype、getCategory,那么这便是一个对象数据类型的辨别器。
对于第一个方法initialize()的形参,便是由若干个函数输入参数的类型辨别器所组成的数组。
public interface ObjectInspector extends Cloneable {
String getTypeName();
Category getCategory();
public static enum Category {
PRIMITIVE,
LIST,
MAP,
STRUCT,
UNION;
private Category() {
}
}
}
复制代码
再来观察DeferredObject的源码。上文提到我们需要在evaluate()方法中实现函数的详细功能,那么首先我们需得到函数的参数值,再根据参数来编写功能逻辑。在DeferredObject的源码中我们发现了get()方法,根据履历我们可以通过此方法来得到函数的参数值。
public static interface DeferredObject {
void prepare(int version) throws HiveException;
Object get() throws HiveException;
};
复制代码
3.实现类中的抽象方法
分析完各个模块,就可以开始重写方法啦。initialize()方法重写如下,其难点在于对函数输入参数类型的判断和如何返回int类型的辨别器对象。
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 判断输入参数的个数
if(arguments.length !=1){
throw new UDFArgumentLengthException("Input Args Length Error!!!");
}
// 判断输入参数的类型
if(!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
throw new UDFArgumentTypeException(0,"Input Args Type Error!!!");
}
//函数本身返回值为int,需要返回int类型的鉴别器对象
return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
}
复制代码
对于输入参数类型的判断,仔细观察上文中的ObjectInspector源码,发现有一个静态枚举类Category,也正是getCategory()方法的返回值类型。
所以该枚举类的作用是用来限定ObjectInspector类型辨别器所辨别类型的效果,我们可以使用getCategory()方法来获取函数参数的类型而且直接调用静态枚举类的成员,比较二者是否雷同来判断函数参数类型是否正确(
arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE))
。在这里我使用ObjectInspector.Category.PRIMITIVE来调用枚举类Category中的PRIMITIVE,由于我们需要限定输入参数的类型为String,其对应的便是PRIMITIVE(原始类型)。
如果在前两步的判断中发现参数不符合要求,我们便可以抛出异常,代码中的两个异常是initialize方法所抛出异常UDFArgumentException的子类,适用于差异的场景,可以更好地起到异常提示效果。
对于返回int类型的辨别器对象,因ObjectInspector是一个接口,所以我们需要调用工厂类中的实例,通过PrimitiveObjectInspectorFactory.javaIntObjectInspector得到。关于何为静态工厂类中的实例各人可以参考以下两篇文章:java静态工厂方法详细剖析;Hive之ObjectInspector接口剖析条记
对于evaluate()方法的实现,因函数自己逻辑简朴,所以其实现难度不大。需要留意的是在使用get()方法获取到参数值后需要toString(),由于从DeferredObject源码中发现get()方法的返回值类型是object,所以需要我们将其转化为String类型。
public Object evaluate(DeferredObject[] arguments) throws HiveException {
return arguments[0].get().toString().length();
}
复制代码
4.在hive的命令行窗口创建函数
首先将代码打成jar包上传到服务器的恣意位置,然后在hive命令利用用如下命令将jar包添加到hive的classpath中。
创建临时函数与开发好的java class关联 ,其中temporary代表创建临时函数,若创建永久函数需省略;mystrlen是我们的函数名;末了需要跟全类名。
运行效果如下:
三、总结
Hive创建自定义函数的逻辑并不难,只需继承相干类,实现相干方法,打成jar包上传集群即可。但在代码编写阶段有一定难度,需要一定的java基础。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4