自定义hive的UDTF函数实现对JSON数组中的JSON对象分离

本文介绍了如何在Hive中自定义一个用户定义表函数(UDTF),用于解析JSON数组。通过继承GenericUDTF并重写initialize和process方法,实现对输入的字符串转换为JSONArray,并逐个处理每个JSON对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我们使用hive进行解析JSON时,虽然有get_json_object函数进行解析,但是功能有限,无法对一个JSON数组进行解析。那么就需要我们自定义一个函数来将数组炸裂开,分成一个个JSON对象去解析。

自定义一个类继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF

重写 initialize,process方法

需要注意的是输出forward必须是一个集合和数组,否则可能会出错。

代码:

package com.royal.hive.udtf;

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.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.json.JSONArray;

import java.util.ArrayList;
import java.util.List;

/**
 * @author csw
 * @time 2022/4/21 19:48
 */
public class ExplodeJSONArray extends GenericUDTF {


    @Override
    public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
        // 进行判断传参是否合法
        if (argOIs.length != 1) {
            throw new UDFArgumentException("传参不合法,只需要一个参数");
        }
        // 判断传参的类型
        // 由于前面控制了传参个数,所以此时是可以确信的直接取第一个参数判断类型,getCategory返回数据类型检查器
        // ObjectInspector.Category.PRIMITIVE基本数据类型
        if (argOIs[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new RuntimeException("参数类型必须为基本数据类型");
        }
        // 将参数对象检查器强转为基本类型对象检查器
        PrimitiveObjectInspector argumentOI = (PrimitiveObjectInspector) argOIs[0];
        // 再去判断是否为String类型
        if (argumentOI.getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {
            throw new RuntimeException("参数必须为String类型数据");
        }

        // 以上均是对使用该函数时的参数和条件判断

        // 定义返回值名称和类型
        List<String> fieldNames = new ArrayList<>();
        List<ObjectInspector> filedOIs = new ArrayList<>();

        fieldNames.add("items");
        filedOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        // 通过对象工厂进行创建一个Struct对象
        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, filedOIs);
    }

    @Override
    public void process(Object[] objects) throws HiveException {

        // 获取值,为什么这里使用数值第一个,因为在初始化时传参就已经限制了条件,这里必只有一个值
        String jsonArray = objects[0].toString();

        // 解析为JSONArray数组
        JSONArray actions = new JSONArray(jsonArray);

        // 如何处理?遍历JSONArray数组,来获取每一个JSON对象
        for (int i = 0; i < actions.length(); i++) {

            // 这里由于我们hive自身有解析JSON的函数,(udtf是炸裂开的,因为这里时循环,所以实际最终输出的是一个数组)
            String[] result = new String[1];
            result[0] = actions.getString(i);
            forward(result);
        }
    }

    @Override
    public void close() throws HiveException {

    }
}

自带函数解析JSON数组:

 SELECT
        explode(
            split(
                regexp_replace(
                    regexp_replace(
                        '[{"website":"www.baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]',
                        '\\[|\\]','' --将字符串的[]总括号去除(替换为‘’)
                        ),
                    '\\}\\,\\{', -- 正则表达式匹配替换,主要目的时将‘,’替换为‘;‘来实现切分
                    '\\}\\;\\{'
                    ),
                '\\;'-- 切分
                ) -- 炸裂开,不然只是一个Array数组
            );

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值