hive wiki -UDTF

1. UDTF介绍

UDTF(User-Defined Table-Generating Functions) 用来解决 输入一行输出多行(On-to-many maping) 的需求。

2. 编写自己需要的UDTF

继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF。
实现initialize, process, close三个方法
UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)。初始化完成后,会调用process方法,对传入的参数进行处理,可以通过forword()方法把结果返回。最后close()方法调用,对需要清理的方法进行清理。
下面是我写的一个UDTF解析json格式,比较纠结的是这个字段很多时候不满足json的定义,有{}值,Null一些情况,做了很多判断,不知道页面展示怎么通过的

package com.taobao.voc.hive.udtf;

public class CopyOfUDTFJson2Rows extends GenericUDTF {

@Override
public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException {

if (args.length != 1 && args.length != 2) {
throw new UDFArgumentLengthException("UDTFSplitValue takes only one or two argument");
}

if (args[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentException("UDTFSplitValue takes string as a parameter");
}

ArrayList<String> fieldNames = new ArrayList<String>();
ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();

fieldNames.add("col");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
}

public void process(Object[] args) throws HiveException {
JSONObject json;
try {
json = new JSONObject(args[0].toString());
if (json.has("bzwd")) {
String bzwd = json.getString("bzwd");
bzwd = new JSONObject(bzwd).getString("data");
JSONObject asks = new JSONObject(bzwd);
String result = "";
for (int i = 0; i < asks.getJSONArray("child").length(); i++) {
result = result + getAskAnswer(asks.getJSONArray("child").getJSONObject(i), 1, (i + 1) + "");
}
String[] split = result.split("\n");
System.out.println(Thread.currentThread().getName() + " " + result);
for (int i = 0; i < split.length; i++) {
String[] temp = { split[i] };
forward(temp);
}
} else {
forward(new String[] { "非标准化问题", "非标准化问题", "非标准化问题", "非标准化问题" });
}
} catch (JSONException e) {
e.printStackTrace();
}

}

/**
* @param pNode
* json数组 level 问答层级 line 问和答属于第几条线路
* */
public String getAskAnswer(JSONObject pNode, int level, String sLine) throws JSONException {
String final_result = "";
if (!pNode.toString().isEmpty() && pNode.has("value") && pNode.has("index")) {
final_result = final_result + "p_id:" + pLine(sLine) + ";s_id:" + sLine + ";level:" + level + ";ask_id:"
+ pNode.get("index") + ";answer_id:" + pNode.get("value") + "\n";
}
// 子节点有子节点,并且子节点是有效的答案(即value字段有值)
if (pNode.has("child") && pNode.has("value")) {
System.out.println(pNode.get("value"));
for (int j = 0; j < pNode.getJSONArray("child").length(); j++) {
if (ifContinue(pNode)) {
final_result = final_result
+ getAskAnswer(pNode.getJSONArray("child").getJSONObject(j), level + 1, sLine(sLine, j));
}
}
}
return final_result;
}
//几个判断节点是否为空和获取p_id的函数省略
}


UDTF有两种使用方法,一种直接放到select后面,一种和lateral view一起使用。

输入格式为JSON
添加jar
add jar /home/taobao/dw_hive/hivelets/smoking/ext/tsa/hivesql/udf/Json2rows.jar;
CREATE TEMPORARY FUNCTION jrow AS 'com.taobao.voc.hive.udtf.UDTFJson2Rows';
1:直接select中使用:
select jrow(ext_attrs) as format_memo from s_tpp_case_universal;
2:和lateral view一起使用:
select id,format_memo,gmt_create,gmt_modified from s_tpp_case_universal lateral view jrow(ext_attrs) b as format_memo;
结果:
p_id:0;s_id:1;level:1;ask_id:dpxxwh1;answer_id:ppxgwt2
p_id:1;s_id:1.1;level:2;ask_id:ppxgwt1;answer_id:pptj2
p_id:1.1;s_id:1.1.1;level:3;ask_id:pptj1;answer_id:pptjtjh2
p_id:1.1.1;s_id:1.1.1.1;level:4;ask_id:pptjh1;answer_id:yyshjg2
p_id:1.1.1.1;s_id:1.1.1.1.1;level:5;ask_id:yyshjg1;answer_id:pptjbtg2
p_id:1.1.1.1.1;s_id:1.1.1.1.1.1;level:6;ask_id:shjgbtg1;answer_id:shcw2
### gmall UDTF 实现方式 gmall 的 UDTF(User Defined Table Function)是一种 Hive 自定义函数,用于处理复杂的数据结构并将其转换为多行输出。以下是关于 gmall UDTF 的实现细节和技术内容: #### 1. 创建永久函数并与 Java 类关联 为了在 Hive 中使用自定义的 UDTF 函数,需要将编写的 Java 类打包成 JAR 文件,并通过 `CREATE FUNCTION` 命令注册到 Hive 中。例如,在 gmall 场景下可以执行如下命令来创建名为 `explode_json_array` 的 UDTF 函数[^2]: ```sql create function explode_json_array as 'com.qi.hive.udtf.ExplodeJSONArray' using jar 'hdfs://worker-13:8020/user/hive/jars/gmall_hive_udtf-1.0-SNAPSHOT.jar'; ``` 此操作会将指定路径下的 JAR 包加载至 Hive 并绑定对应的 Java 类。 --- #### 2. 编写 UDTF 的核心逻辑 UDTF 的实现通常基于 Apache Hive 提供的 `GenericUDTF` 抽象类。开发者需继承该类并重写其三个主要方法:`initialize`、`process` 和 `close`[^3]。 ##### (1)初始化阶段 (`initialize`) 在 `initialize` 方法中完成以下任务: - 验证输入参数的数量和类型是否符合预期; - 定义输出列的数量及其数据类型; - 返回两组列表——分别表示输出列名称和对应的数据类型。 示例代码片段展示如何设置输出列的信息: ```java @Override public void configure(JobConf job) {} @Override public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException { // 输入校验 if (args.length != 1 || !(args[0] instanceof ListObjectInspector)) { throw new UDFArgumentException("Input must be a list of JSON objects"); } // 设置输出列名及类型 ArrayList<String> fieldNames = new ArrayList<>(); ArrayList<ObjectInspector> fieldOIs = new ArrayList<>(); fieldNames.add("exploded_value"); fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs); } ``` --- ##### (2)处理阶段 (`process`) `process` 方法负责接收单条输入记录并通过调用 `forward` 将多个结果发送给下游处理器。对于 gmall 的场景而言,假设输入是一个 JSON 数组,则可以通过遍历数组中的每一项并将它们逐一转发出去。 下面提供了一个简单的例子说明这一过程: ```java @Override public void process(Object input) throws HiveException { try { @SuppressWarnings("unchecked") List<String> jsonArray = (List<String>) ((ArrayList<?>) input).clone(); for (String item : jsonArray) { forward(new String[]{item}); } } catch (Exception e) { throw new HiveException(e.getMessage()); } } ``` 在此过程中需要注意异常捕获机制以确保程序稳定性。 --- ##### (3)清理阶段 (`close`) 虽然大多数情况下不需要特别关注 `close` 方法的行为,但在某些特殊需求下可能需要用到它来进行资源释放或其他收尾工作。 ```java @Override public void close() throws HiveException {} ``` --- #### 3. 使用 get_json_object 解析字段 当动作日志表被过滤出包含特定 action 字段的部分之后,可进一步利用内置函数 `get_json_object` 来提取嵌套于 JSON 结构内部的各项属性值[^1]。这一步骤有助于最终形成标准化的关系型表格形式以便后续分析查询。 --- #### 总结 综上所述,gmall 的 UDTF 实现有赖于编写合适的 Java 类文件以及正确配置 Hive 环境使其能够识别这些扩展功能模块。整个流程涵盖了从基础架构搭建直至实际应用部署等多个方面的工作内容。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值