为了验证UDTF的功能,咱们要先把表和数据都准备好:
- 新建名为t16的表:
create table t16(
person_name string,
string_field string
)
row format delimited
fields terminated by ‘|’
stored as textfile;
- 本地新建文本文件016.txt,内容如下:
tom|1:province:guangdong
jerry|2:city:shenzhen
john|3
- 导入数据:
load data
local inpath ‘/home/hadoop/temp/202010/25/016.txt’
overwrite into table t16;
- 数据准备完毕,开始编码;
UDTF开发的关键点
-
需要继承GenericUDTF类;
-
重写initialize方法,该方法的入参只有一个,类型是StructObjectInspector,从这里可以取得UDTF作用了几个字段,以及字段类型;
-
initialize的返回值是StructObjectInspector类型,UDTF生成的每个列的名称和类型都设置到返回值中;
-
重写process方法,该方法中是一进多出的逻辑代码,把每个列的数据准备好放在数组中,执行一次forward方法,就是一行记录;
-
close方法不是必须的,如果业务逻辑执行完毕,可以将释放资源的代码放在这里执行;
-
接下来,就按照上述关键点开发UDTF;
一列拆成多列
-
接下来要开发的UDTF,名为udf_wordsplitsinglerow,作用是将入参拆分成多个列;
-
下图红框中是t16表的一条原始记录的string_field字段,会被udf_wordsplitsinglerow处理:
- 上面红框中的字段被UDTF处理处理后,一列变成了三列,每一列的名称如下图黄框所示,每一列的值如红框所示:
-
以上就是咱们马上就要开发的功能;
-
打开前文创建的hiveudf工程,新建WordSplitSingleRow.java:
package com.bolingcavalry.hiveudf.udtf;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.*;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;
import java.util.List;
/**
-
@Description: 把指定字段拆成多列
-
@author: willzhao E-mail: zq2599@gmail.com
-
@date: 2020/11/5 14:43
*/
public class WordSplitSingleRow extends GenericUDTF {
private PrimitiveObjectInspector stringOI = null;
private final static String[] EMPTY_ARRAY = {“NULL”, “NULL”, “NULL”};
/**
-
一列拆成多列的逻辑在此
-
@param args
-
@throws HiveException
*/
@Override
public void process(Object[] args) throws HiveException {
String input = stringOI.getPrimitiveJavaObject(args[0]).toString();
// 无效字符串
if(StringUtils.isBlank(input)) {
forward(EMPTY_ARRAY);
} else {
// 分割字符串
String[] array = input.split(“:”);
// 如果字符串数组不合法,就返回原始字符串和错误提示
if(null==array || array.length<3) {
String[] errRlt = new String[3];
errRlt[0] = input;
errRlt[1] = “can not split to valid array”;
errRlt[2] = “-”;
forward(errRlt);
} else {
forward(array);
}
}
}
/**
-
释放资源在此执行,本例没有资源需要释放
-
@throws HiveException
*/
@Override
public void close() throws HiveException {
}
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
List<? extends StructField> inputFields = argOIs.getAllStructFieldRefs();
// 当前UDTF只处理一个参数,在此判断传入的是不是一个参数
if (1 != inputFields.size()) {
throw new UDFArgumentLengthException(“ExplodeMap takes only one argument”);
}
// 此UDTF只处理字符串类型
if(!Category.PRIMITIVE.equals(inputFields.get(0).getFieldObjectInspector().getCategory())) {
throw new UDFArgumentException(“ExplodeMap takes string as a parameter”);
}
stringOI = (PrimitiveObjectInspector)inputFields.get(0).getFieldObjectInspector();
//列名集合
ArrayList fieldNames = new ArrayList();
//列对应的value值
ArrayList fieldOIs = new ArrayList();
// 第一列的列名
fieldNames.add(“id”);
// 第一列的inspector类型为string型
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
// 第二列的列名
fieldNames.add(“key”);
// 第二列的inspector类型为string型
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
// 第三列的列名
fieldNames.add(“value”);
// 第三列的inspector类型为string型
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
}
}
- 上述代码中的重点是process方法,取得入参后用冒号分割字符串,得到数组,再调用forward方法,就生成了一行记录,该记录有三列;
验证UDTF
接下来将WordSplitSingleRow.java部署成临时函数并验证;
-
编码完成后,在pom.xml所在目录执行命令mvn clean package -U;
-
在target目录得到文件hiveudf-1.0-SNAPSHOT.jar
-
将jar下载到hive服务器,我这里放在此目录:/home/hadoop/udf/
-
在hive会话模式执行以下命令添加本地jar:
add jar /home/hadoop/udf/hiveudf-1.0-SNAPSHOT.jar;
- 部署临时函数:
create temporary function udf_wordsplitsinglerow as ‘com.bolingcavalry.hiveudf.udtf.WordSplitSingleRow’;
- 执行以下SQL验证:
select udf_wordsplitsinglerow(string_field) from t16;
- 结果如下,可见每一行记录的string_field字段都被分割成了id、key、value三个字段:
hive> select udf_wordsplitsinglerow(string_field) from t16;
OK
id key value
1 province guangdong
2 city shenzhen
3 can not split to valid array -
Time taken: 0.066 seconds, Fetched: 3 row(s)
关键点要注意
- 值得注意的是,UDTF不能和其他字段同时出现在select语句中,例如以下的SQL会执行失败:
select person_name,udf_wordsplitsinglerow(string_field) from t16;
- 错误信息如下:
hive> select person_name,udf_wordsplitsinglerow(string_field) from t16;
FAILED: SemanticException [Error 10081]: UDTF’s are not supported outside the SELECT clause, nor nested in expressions
- 如果希望得到UDTF和其他字段的结果,可以使用LATERAL VIEW语法,完整SQL如下:
select t.person_name, udtf_id, udtf_key, udtf_value
from (
select person_name, string_field
from t16
) t LATERAL VIEW udf_wordsplitsinglerow(t.string_field) v as udtf_id, udtf_key, udtf_value;
- 查询结果如下,可见指定字段和UDTF都能显示:
hive> select t.person_name, udtf_id, udtf_key, udtf_value
from (
select person_name, string_field
from t16
) t LATERAL VIEW udf_wordsplitsinglerow(t.string_field) v as udtf_id, udtf_key, udtf_value;
OK
t.person_name udtf_id udtf_key udtf_value
tom 1 province guangdong
jerry 2 city shenzhen
john 3 can not split to valid array -
Time taken: 0.122 seconds, Fetched: 3 row(s)
一列拆成多行(每行多列)
-
前面咱们试过了将string_field字段拆分成id、key、value三个字段,不过拆分后总行数还是不变,接下来的UDTF,是把string_field拆分成多条记录,然后每条记录都有三个字段;
-
需要导入新的数据到t16表,新建文本文件016_multi.txt,内容如下:
tom|1:province:guangdong,4:city:yangjiang
jerry|2:city:shenzhen
john|3
- 在hive会话窗口执行以下命令,会用016_multi.txt的内容覆盖t16表已有内容:
load data
local inpath ‘/home/hadoop/temp/202010/25/016_multi.txt’
overwrite into table t16;
- 此时的数据如下图所示,红框中是一条记录的string_field字段值,咱们接下来要开发的UDTF,会先用逗号分隔,得到的就是1:province:guangdong和4:city:yangjiang这两个字符串,接下来对每个字符串用冒号分隔,就会得到两条id、key、value这样的记录,也就是多行多列:
- 预期中的UDTF结果如下图所示,红框和黄框这两条记录都来自一条记录的string_field字段值:
- 接下来开始编码,新建WordSplitMultiRow.java,代码如下,可见和WordSplitSingleRow的差异仅在process方法,WordSplitMultiRow的process中执行了多次forward,因此有了多条记录:
package com.bolingcavalry.hiveudf.udtf;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.*;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;
import java.util.List;
/**
-
@Description: 把指定字段拆成多行,每行有多列
-
@author: willzhao E-mail: zq2599@gmail.com
-
@date: 2020/11/5 14:43
*/
public class WordSplitMultiRow extends GenericUDTF {
private PrimitiveObjectInspector stringOI = null;
private final static String[] EMPTY_ARRAY = {“NULL”, “NULL”, “NULL”};
/**
-
一列拆成多列的逻辑在此
-
@param args
-
@throws HiveException
*/
@Override
public void process(Object[] args) throws HiveException {
String input = stringOI.getPrimitiveJavaObject(args[0]).toString();
// 无效字符串
if(StringUtils.isBlank(input)) {
forward(EMPTY_ARRAY);
} else {
// 用逗号分隔
String[] rowArray = input.split(“,”);
// 处理异常
if(null==rowArray || rowArray.length<1) {
String[] errRlt = new String[3];
errRlt[0] = input;
errRlt[1] = “can not split to valid row array”;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/9e03deb7d36ee30406e25122f763e706.jpeg)
Java高频面试专题合集解析:
当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!
更多Java架构进阶资料展示
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/9e03deb7d36ee30406e25122f763e706.jpeg)
Java高频面试专题合集解析:
[外链图片转存中…(img-sDQskf0h-1711978018654)]
当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!
[外链图片转存中…(img-3DAgDN5w-1711978018654)]
更多Java架构进阶资料展示
[外链图片转存中…(img-OPOcP1em-1711978018655)]
[外链图片转存中…(img-14eNwp90-1711978018655)]
[外链图片转存中…(img-apaCqkoJ-1711978018655)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!