1.什么时候用UDTF
你可能会遇到下面这样的json字符串解析
{"a":[{},{},{}],"b":{},"c":0, "d":null, "e": "lll",}
假如,让你把字段a的数组炸裂成多行,再加一条,去掉数组的第1个元素。
想一下,你要如何完成这个需求?
此时,如果你使用hive提供的get_json_object或者json_tuple,甚至你再用一些nvl等函数,你发现很难解析出你想要的数据,即便勉强实现,你会发现解析效率很低,原因后面会讲到。
2.开发自定义函数UDTF
2.1 导入maven依赖
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>${hive.version}</version>
</dependency>
</dependencies>
2.2 代码实现
public class UDTF extends GenericUDTF {
//返回一个字段,若为多个可更改
private String[] resultArray = new String[1];
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
List<String> fieldNames = Lists.newLinkedList();
//添加字段
fieldNames.add("output");
List<ObjectInspector> fieldsType = Lists.newLinkedList();
//添加字段类型 fieldsType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
// 返回列名和列类型
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldsType);
}
@Override
public void process(Object[] args) throws HiveException {
if(args[0] == null) {
return;
}
String valueOutput = args[0].toString();
String str = valueOutput;
//此行为伪代码,按照你的业务逻辑修改即可
array = valueOutput.toarray
arraySize = array.size()
for (int i = 0; i < ArraySize; i++) {
//核心代码,实现炸裂为多行
resultArray[0] = array [i]
forward(resultArray);
}
}
@Override
public void close() throws HiveException {
}
}
2.3 打包jar
2.4 上传jar包到hdfs
2.5 注册自定义函数
注册临时自定义函数UDTF
add jar /opt/data-hive/hive-udf-1.0-SNAPSHOT-jar-with-dependencies.jar;
create temporary function rule_logic_output_flat as 'com.warehouse.hive.udtf.UDTF' using jar 'hdfs://linux:8020/user/hive/jars/hive-udf-1.0-SNAPSHOT-jar-with-dependencies.jar';
注册永久自定义函数UDTF(需要重启集群,用临时函数开发,正式部署用永久函数)
create function udtf_yours as 'com.warehouse.hive.udtf.UDTF' using jar 'hdfs://linux:8020/user/hive/jars/hive-udf-1.0-SNAPSHOT-jar-with-dependencies.jar';
3.为什么自定义函数更快
原因是,当你调用很多hive固有函数去实现一个复杂解析的时候,有许多的对象的方法创建及调用,但是如果你用自定义函数,可以一次调用完成所有解析。
建议,解析复杂数据的时候,或者说当你使用超过4-5个以上的内置函数去解析数据时,采用自定义函数实现。
十八般兵器和手枪你选什么?