如何编写一个udf请参考上一篇文章:
hive自定义UDF函数遇到的坑
下面是具体的UDTD的建立:
package com.udf.test;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.List;
public class UdtfTest extends GenericUDTF {
static final Log log = LogFactory.getLog(UdtfTest.class.getName());
/**
* 其中initialize方法和UDF中类似,主要是判断输入类型并确定返回的字段类型
**/
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
List<String> colName = Lists.newLinkedList();
colName.add("item_id");
colName.add("item_name");
colName.add("group");
colName.add("item_detail");
List<ObjectInspector> resType = Lists.newLinkedList();
resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
// 返回分别为列名 和 列类型
return ObjectInspectorFactory.getStandardStructObjectInspector(colName, resType);
}
/**
* process方法对udft函数输入的每一样进行操作,通过调用forward方法返回一行或多行数据
*/
@Override
public void process(Object[] args) throws HiveException {
if (args[0] == null) {
return;
}
log.info("入参信息="+args.toString());
String[] strArr = new String[4];
String strings = args[0].toString();
log.info("需要转换数组的参数="+strings);
// 引入了阿里巴巴的json框架,导入自己的jar就可以了
JSONArray jsonArray = JSONArray.parseArray(strings);
for (int i = 0; i < jsonArray.size(); i++) {
Object oneObj = jsonArray.get(i);
if (null == oneObj) {
continue;
} else {
JSONObject jsonObject = JSONObject.parseObject(oneObj.toString());
strArr[0]= String.valueOf(jsonObject.get("item_id"));
strArr[1]= String.valueOf(jsonObject.get("item_name"));
strArr[2]= String.valueOf(jsonObject.get("group"));
strArr[3]= String.valueOf(jsonObject.get("item_detail"));
forward(strArr);
}
}
}
/**
* close方法在process调用结束后调用,用于进行其它一些额外操作,只执行一次。
*/
@Override
public void close() throws HiveException {
}
}
此函数生成后怎么使用:
select a.pid,a.service_code,b.e,b.f,b.e,b.g from ods.tpdg_service_call_info a lateral view udtf_test(get_json_object(a.result_data, ‘$.risk_items’)) b as e,f,e,g
where a.id=6615;
注意点: 1、as e,f,e,g 这里的个数必须与 initialize设置的个数一致
2、返回的类容key和value不能有重复的,因为lateral view 对字段做了分组处理,如果相同的值,相同的key就会报错
这种类似的功能还可以根据explode函数实现,但是此函数有个缺陷,只能读取数组的字段或者通过split函数生成的数组,太复杂的json格式就不能识别了。
select explode(split(regexp_replace(get_json_object(result_data, ‘$.risk_items’),’\[|\]’,’’),’\},\{’)) from ods.tpdg_service_call_info where id=6615;
这句sql只能解析这种单层的数据: [{“name”:“zhangsan”},{“name”:“lisi”}]