Hive自定义UDTF解析json不定长数组

24 篇文章 4 订阅
22 篇文章 2 订阅

Hive自定义UDTF解析json不定长数组

一、UDTF函数概述

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

二、添加pom.xml依赖


    <dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.2</version>
        </dependency>
    </dependencies>

三、继承GenericUDTF实现解析json不定长数组

package com.hive;

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.StructField;
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;

public class myUDTF extends GenericUDTF {

    /**
     * 作用:1.检查入参是否符合要求,如果不符合,可以进行通知
     *      2.返回ObjectInspector,代表每行中内容的类型
     *
     *      要求传入的必须是一个String
     *
     * @param argOIs
     * @return
     * @throws UDFArgumentException
     */
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {

        //获取函数传入的所有字段
        List<? extends StructField> inputFields = argOIs.getAllStructFieldRefs();

        //判断函数传入的是否是一个字段
        if (inputFields.size() != 1){
            throw new UDFArgumentException("此函数只能传入一列!");
        }

        //判断传入的字段是否是字符串
        if (!"string".equals(inputFields.get(0).getFieldObjectInspector().getTypeName())){
            throw new UDFArgumentException("此函数只能传入一列字符串");
        }

        //返回的是N行1列,每行都是只有一列(string)

        //每行的每列的名称
        List<String> fieldNames = new ArrayList<>();
        fieldNames.add("jsonObjectStr");

        //每行的每列的类型
        List<ObjectInspector> fieldOIS = new ArrayList<>();
        fieldOIS.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,fieldOIS);
    }

    //构造一个容器,存放输出的每行内容
    private String [] result = new String[1];


    //process: 生成UDTF返回的每行内容,生成后,调用forward(),将结果传给其他的运算符运算!
    public void process(Object[] args) throws HiveException {

        //获取函数传入的JsonArrayStr
        String jsonArrayStr = args[0].toString();

        //将JsonArrayStr转换为JsonArray对象
        JSONArray jsonArray = new JSONArray(jsonArrayStr);

        //遍历jsonArray,取出每一个JsonObject代表的str
        for (int i=0;i<jsonArray.length();i++){

            String jsonObjectStr = jsonArray.getJSONObject(i).toString();

            result[0] = jsonObjectStr;

            forward(result);
        }

    }

	//关闭资源
    public void close() throws HiveException {

    }
}

四、在Hive创建自定义函数

①将上述代码打包上传到hive家目录下的auxlib文件夹内($HIVE_HOME/auxlib)

如果不存在需要自己手动创建,重启hive的服务,hive会自动读取auxlib目录下的jar包

②创建永久函数

​ 注意: 函数是有库的范围,自定义的函数,在哪个库定义,只能在哪个库用! 或使用 库名.函数名

create function 函数名 as '函数全类名';

create function explode_array as 'com.hive.myUDTF';

五、函数使用

SELECT 
		GET_JSON_OBJECT(line,'$.common.ar'), 
		GET_JSON_OBJECT(line,'$.common.ba'),
		GET_JSON_OBJECT(line,'$.common.ch') ,
		GET_JSON_OBJECT(line,'$.common.md') ,
		GET_JSON_OBJECT(line,'$.common.mid'), 
		GET_JSON_OBJECT(line,'$.common.os') ,
		GET_JSON_OBJECT(line,'$.common.uid') ,
		GET_JSON_OBJECT(line,'$.common.vc') ,
		
		GET_JSON_OBJECT(line,'$.page.during_time') ,
		GET_JSON_OBJECT(line,'$.page.item') ,
		GET_JSON_OBJECT(line,'$.page.item_type') ,
		GET_JSON_OBJECT(line,'$.page.last_page_id') ,
		GET_JSON_OBJECT(line,'$.page.page_id') ,		
		GET_JSON_OBJECT(line,'$.page.sourceType') ,	
		
		GET_JSON_OBJECT(line,'$.ts') ,
		
		GET_JSON_OBJECT(jsonObjectStr,'$.displayType') ,
		GET_JSON_OBJECT(jsonObjectStr,'$.item') ,
		GET_JSON_OBJECT(jsonObjectStr,'$.item_type') ,
		GET_JSON_OBJECT(jsonObjectStr,'$.order') 
		
	FROM ods_log  
    lateral  view  explore_arr(GET_JSON_OBJECT(line,'$.displays')) tmp as jsonObjectStr
	WHERE  GET_JSON_OBJECT(line ,'$.displays') is not null 
	       AND  dt='2021-01-04';

-----------------------------------------------------------更新----------------------------------------------------------------------------

对json数组字符串数组进行处理,拆分后使用explore函数处理(explore函数也是UDTF函数)

SELECT 
		GET_JSON_OBJECT(line,'$.common.ar'), 
		GET_JSON_OBJECT(line,'$.common.ba'),
		GET_JSON_OBJECT(line,'$.common.ch') ,
		GET_JSON_OBJECT(line,'$.common.md') ,
		GET_JSON_OBJECT(line,'$.common.mid'), 
		GET_JSON_OBJECT(line,'$.common.os') ,
		GET_JSON_OBJECT(line,'$.common.uid') ,
		GET_JSON_OBJECT(line,'$.common.vc') ,
		
		GET_JSON_OBJECT(line,'$.page.during_time') ,
		GET_JSON_OBJECT(line,'$.page.item') ,
		GET_JSON_OBJECT(line,'$.page.item_type') ,
		GET_JSON_OBJECT(line,'$.page.last_page_id') ,
		GET_JSON_OBJECT(line,'$.page.page_id') ,		
		GET_JSON_OBJECT(line,'$.page.sourceType') ,	
		
		GET_JSON_OBJECT(line,'$.ts') ,
		
		GET_JSON_OBJECT(jsonObjectStr,'$.displayType') ,
		GET_JSON_OBJECT(jsonObjectStr,'$.item') ,
		GET_JSON_OBJECT(jsonObjectStr,'$.item_type') ,
		GET_JSON_OBJECT(jsonObjectStr,'$.order') 	 
	 

    --REGEXP_REPLACE( GET_JSON_OBJECT(line,'$.displays') ,'\\[|\\]' ,'' )
    --REGEXP_REPLACE( REGEXP_REPLACE( GET_JSON_OBJECT(line,'$.displays') ,'\\[|\\]' ,'' ),'\\}\\,\\{' ,'\\}\\!\\{')
    --split( REGEXP_REPLACE( REGEXP_REPLACE( GET_JSON_OBJECT(line,'$.displays') ,'\\[|\\]' ,'' ),'\\}\\,\\{' ,'\\}\\!\\{'),'\\!' )
    
from ods_log 
 lateral  view  explode( split( REGEXP_REPLACE( REGEXP_REPLACE( GET_JSON_OBJECT(line,'$.displays') ,'\\[|\\]' ,'' ),'\\}\\,\\{' ,'\\}\\!\\{'),'\\!' ) ) tmp as jsonObjectStr
where  GET_JSON_OBJECT(line ,'$.displays') is not null 
        and dt='2021-01-04'
;
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Hive中的UDTF是用户定义的表生成函数,可以将一行输入转换为多行输出。以下是Hive自定义UDTF函数的一些步骤: 1. 创建一个Java类,实现org.apache.hadoop.hive.ql.exec.UDTF接口。该接口需要实现initialize方法、process方法和close方法。 2. 在initialize方法中,可以获取函数的参数,例如输入列的名称和类型等。 3. 在process方法中,可以实现业务逻辑,并将结果输出到Collector对象中。 4. 在close方法中,可以进行一些清理工作。 5. 将Java类打包成jar文件,并上传到Hive中。 6. 在Hive中,使用ADD JAR命令加载jar文件。 7. 创建UDTF函数,使用CREATE FUNCTION命令,并指定INPUT格式和OUTPUT格式等参数。 8. 在Hive中使用UDTF函数,例如使用SELECT语句进行查询。 下面是一个简单的例子: ```java import org.apache.hadoop.hive.ql.exec.UDFArgumentException; import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException; import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException; import org.apache.hadoop.hive.ql.exec.UDFReturnType; import org.apache.hadoop.hive.ql.exec.description.JavaUDF; 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.ArrayList; @JavaUDF(description = "Split a string and output multiple rows", name = "explode_string", returnType = UDFReturnType.TABLE) public class ExplodeStringUDTF extends GenericUDTF { @Override public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException { if (args.length != 1) { throw new UDFArgumentLengthException("explode_string takes only one argument"); } if (!args[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)) { throw new UDFArgumentTypeException(0, "explode_string takes only primitive types"); } ArrayList<String> fieldNames = new ArrayList<String>(); ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>(); fieldNames.add("value"); fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs); } @Override public void process(Object[] args) throws HiveException { String input = args[0].toString(); String[] tokens = input.split(","); for (String token : tokens) { String[] fields = {token}; forward(fields); } } @Override public void close() throws HiveException { } } ``` 在Hive中,可以使用以下命令创建UDTF函数: ```sql CREATE FUNCTION explode_string AS 'com.example.ExplodeStringUDTF' USING JAR 'hdfs:///path/to/jar/file.jar'; ``` 使用以下命令查询数据: ```sql SELECT * FROM (SELECT 'a,b,c' AS input) s LATERAL VIEW explode_string(s.input) myTable AS myColumn; ``` 上述查询结果为: ``` myColumn ------- a b c ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值