编写hive自定义函数的时候,查阅很多文档都没有写清楚,现将代码过程进行编写,方便后续复习
1、内置函数
hive本身会自带一些内置函数,由于数量有限,需要编写自定义函数来方便公司的业务扩展。
2、用户自定义函数类别
UDF(User-Defined-Function) 一进一出
UDAF(User-Defined Aggregation Function) 聚合函数,多进一出,如:count/max/min
UDTF(User-Defined Table-Generating Functions) 炸裂函数,一进多出,如:explode()
3、官网文档
HivePlugins - Apache Hive - Apache Software Foundation
4、编程实现步骤
导入pom.xml文件。这是我的项目,仅供参考
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gyyx</groupId>
<artifactId>get_grid_line</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Maven</name>
<url>http://maven.apache.org/</url>
<inceptionYear>2001</inceptionYear>
<distributionManagement>
<site>
<id>website</id>
<url>scp://webhost.company.com/www/website</url>
</site>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
</project>
编写udf函数代码
需要继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF包,实现类中的抽象方法
package gyyx.utils;
import org.apache.hadoop.hive.ql.exec.Description;
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;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
/**
* @author niehandong
* @since 1.0.0
*/
@Description(name = "get_grid_line", value = "Returns a formatted string from multiple input strings")
public class GridLines extends GenericUDF {
/*
这个方法主要是对自定义的UDF函数进行初始化,目的是指定调用完函数返回的值的类型
需求:传入多个字符串,返回一个新的字符串
*/
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 确保至少有3个参数
if (arguments.length != 3) {
throw new UDFArgumentException("get_grid_line requires exactly 3 arguments.");
}
// 使用PrimitiveObjectInspectorFactory工厂类,获取String类型的ObjectInspector
for (ObjectInspector oi : arguments) {
if (!oi.getCategory().equals(ObjectInspector.Category.PRIMITIVE) ||
!((PrimitiveObjectInspector) oi).getPrimitiveCategory().equals(PrimitiveObjectInspector.PrimitiveCategory.STRING)) {
throw new UDFArgumentException("All arguments must be strings.");
}
}
return PrimitiveObjectInspectorFactory.javaStringObjectInspector; // 返回类型为String
}
/*
该方法是自定义UDF的核心方法,目的是实现自定义UDF的逻辑
arguments将来会有多个参数
*/
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
String longitude = arguments[0].get().toString();
String latitude = arguments[1].get().toString();
String type = arguments[2].get().toString();
return longitude+latitude+type+"随机数";
}
@Override
public String getDisplayString(String[] children) {
return "这是我们自己使用新版本写法自定义的UDF函数,接收多个字符串并返回拼接结果";
}
}
测试数据:
首先在hive命令行创建函数。我采用的是将jar上传到hdfs上,通过hdfs注册。期间试过通过本地路径上传。没有成功,报错显示只能通过hdfs路径上传
#方法一
#TEMPORARY 为临时函数,关闭连接后就失效了
CREATE TEMPORARY FUNCTION get_grid_line as 'gyyx.utils.GridLines' using jar 'hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar';
#方法二:
# 添加jar包路径
ADD JAR hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar;
#创建函数,注意这个不是临时函数,需要将TEMPORARY 加上才是临时函数
CREATE FUNCTION get_grid_line as 'gyyx.utils.GridLines';
hive> select get_grid_line('116.301768','40.055783','rr');
OK
116.30176840.055783rr随机数
Time taken: 2.572 seconds, Fetched: 1 row(s)

编写udtf函数
package gyyx.utils;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;
import java.util.List;
/**
* @author niehandong
* @since 1.0.0
*/
public class GridLinesUDTF extends GenericUDTF {
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
//创建一个List集合存储结果列的名字
List<String> colNames = new ArrayList<>();
//创建一个集合存储每一列的数据类型
List<ObjectInspector> colTypes = new ArrayList<>();
//向集合中添加元素,设置列的名字以及类型
colNames.add("id");
colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
colNames.add("name");
colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
colNames.add("cardId");
colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
//返回一个对象,该对象封装了列的名字以及列的类型
return ObjectInspectorFactory.getStandardStructObjectInspector(colNames, colTypes);
}
@Override
public void process(Object[] args) throws HiveException {
//创建一个数组,存储每一列的数据
//因为结果一行数据中有3列,需要创建一个长度为3的数组,用来存储我们处理过的一行三列数据
String[] rows = new String[3];
//args[0]是传入的第一个列数据
String col = args[0].toString();
String[] infos = col.split(",");
//遍历切分后的数组,得到每一个用户信息
for (String info : infos) {
String[] strings = info.split("#");
for (String i : strings) {
if(i.startsWith("M")){ // M1001
rows[0] = i.substring(1);
}else if(i.startsWith("S")){
rows[2] = i.substring(1);
}else {
rows[1] = i;
}
}
//forward(Object o) 调用概述方法,将输出的一行数据,封装成一个数组,传入到forward方法中,给hive后续处理
forward(rows);
}
}
@Override
public void close() throws HiveException {
}
}
测试数据:
#方法一
#TEMPORARY 为临时函数,关闭连接后就失效了
CREATE TEMPORARY FUNCTION get_grid_lineudf as 'gyyx.utils.GridLinesUDTF' using jar 'hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar';
#方法二:
# 添加jar包路径
ADD JAR hdfs://ip:4007/user/hive/warehouse/get_grid_line-1.0-SNAPSHOT.jar;
#创建函数,注意这个不是临时函数,需要将TEMPORARY 加上才是临时函数
CREATE FUNCTION get_grid_lineudf as 'gyyx.utils.GridLinesUDTF';
hive> select get_grid_lineudf('M1001#xiaohu#S324231212,lkd#M1002#S2543412432,S21312312412#M1003#bfy');
OK
1001 xiaohu 324231212
1002 lkd 2543412432
1003 bfy 21312312412
Time taken: 0.175 seconds, Fetched: 3 row(s)

1014

被折叠的 条评论
为什么被折叠?



