hive学习笔记之十一:UDTF(1)

// 第二列的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部署成临时函数并验证;

  1. 编码完成后,在pom.xml所在目录执行命令mvn clean package -U;

  2. 在target目录得到文件hiveudf-1.0-SNAPSHOT.jar

  3. 将jar下载到hive服务器,我这里放在此目录:/home/hadoop/udf/

  4. 在hive会话模式执行以下命令添加本地jar:

add jar /home/hadoop/udf/hiveudf-1.0-SNAPSHOT.jar;

  1. 部署临时函数:

create temporary function udf_wordsplitsinglerow as ‘com.bolingcavalry.hiveudf.udtf.WordSplitSingleRow’;

  1. 执行以下SQL验证:

select udf_wordsplitsinglerow(string_field) from t16;

  1. 结果如下,可见每一行记录的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”;

errRlt[2] = “-”;

forward(errRlt);

} else {

// rowArray的每个元素,都是"id🔑value"这样的字符串

for(String singleRow : rowArray) {

// 要确保字符串有效

if(StringUtils.isBlank(singleRow)) {

forward(EMPTY_ARRAY);

} else {

// 分割字符串

String[] array = singleRow.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);

}

}

验证UDTF

接下来将WordSplitMultiRow.java部署成临时函数并验证;

  1. 编码完成后,在pom.xml所在目录执行命令mvn clean package -U;

  2. 在target目录得到文件hiveudf-1.0-SNAPSHOT.jar

  3. 将jar下载到hive服务器,我这里放在此目录:/home/hadoop/udf/

  4. 如果还在同一个hive会话模式,需要先清理掉之前的jar和函数:

drop temporary function if exists udf_wordsplitsinglerow;

delete jar /home/hadoop/udf/hiveudf-1.0-SNAPSHOT.jar;

  1. 在hive会话模式执行以下命令添加本地jar:

add jar /home/hadoop/udf/hiveudf-1.0-SNAPSHOT.jar;

  1. 部署临时函数:

create temporary function udf_wordsplitmultirow as ‘com.bolingcavalry.hiveudf.udtf.WordSplitMultiRow’;

  1. 执行以下SQL验证:

select udf_wordsplitmultirow(string_field) from t16;

  1. 结果如下,可见每一行记录的string_field字段都被分割成了id、key、value三个字段:

hive> select udf_wordsplitmultirow(string_field) from t16;

OK

id key value

1 province guangdong

4 city yangjiang

2 city shenzhen

3 can not split to valid array -

Time taken: 0.041 seconds, Fetched: 4 row(s)

  1. 用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_wordsplitmultirow(t.string_field) v as udtf_id, udtf_key, udtf_value;

  1. 结果如下,符合预期:

hive> select t.person_name, udtf_id, udtf_key, udtf_value

from (

select person_name, string_field 
线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

一线互联网P7面试集锦+各种大厂面试集锦

学习笔记以及面试真题解析

tched: 4 row(s)

  1. 用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_wordsplitmultirow(t.string_field) v as udtf_id, udtf_key, udtf_value;

  1. 结果如下,符合预期:

hive> select t.person_name, udtf_id, udtf_key, udtf_value

from (

select person_name, string_field 
线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

[外链图片转存中…(img-aY8oXz5P-1714297296037)]

一线互联网P7面试集锦+各种大厂面试集锦

[外链图片转存中…(img-H3XRUGXU-1714297296037)]

学习笔记以及面试真题解析

[外链图片转存中…(img-aOhV7mV7-1714297296038)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 29
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值