hive:自定义函数去处理表数据

一、自定义函数

1、步骤

(1)在idea中写好的函数打包成jar包,把包放至hive中 add jar “包在Linux中的路径”

 

(2)创造一个函数用来运行包和传参:

create temporary function myudtf as "com.shujia.udf.MyUDTFDemo"; //后面是Java文价在包中的位置

(3)当函数去使用,传入表的数据

select myudf(word,",") from wordcount;

2、实战

(1)UDF:表示传入一行数据,在通过数据计算逻辑传出一行数据

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.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

/**
 * 需求:
 * 传入一列数据,返回该列数据中每行的字符串长度
 */
public class MyNewUDFDemo extends GenericUDF {


    /**
     *  initialize :实例化UDF对象
     *
     * 参数 arguments 该参数为HIVE注册后的方法传入参数,是一个检查器对象的数组
     * ObjectInspector 返回的类型是指 我们数据输出的数据类型。
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {

        // 如果传入参数长度不为1 那么就返回UDF长度异常,并提示异常信息
        if(arguments.length != 1){
            throw new UDFArgumentLengthException("传入参数长度不够...");
        }

        // 获取一个参数,比对传入参数的数据类型
        /**
         *ObjectInspector.Category.
         * PRIMITIVE : hive中String、int、float、double、boolean等基础数据类型
         * LIST : 数组类型
         * MAP : Map类型
         * STRUCT : 结构体数据类型
         */
        if(!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
            /**
             *
             * UDFArgumentTypeException(int argumentId, String message) 
             * 异常对象需要传入两个参数:
             *      int argumentId 表示 参数的位置 ObjectInspector中的下标
             *      String message 表示 异常提示信息
             */
            throw new UDFArgumentTypeException(0,"参数类型不正确...");
        }

        // 可以通过查看GenericUDF 其他子类实现去比对查看继承关系快捷键 Ctrl + H
        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

    /**
     * evaluate方法可以去实现数据的处理逻辑
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        // 获取第0位参数的值,注意需要通过get()获取
        String columns1 = arguments[0].get().toString();

        return columns1.length();
    }

    @Override
    public String getDisplayString(String[] children) {
        return "展现执行计划及流程...";
    }
}

使用命令

HIVE中的命令:
 *      ① 添加打包好的jar 至hive lib中 add jar /usr/local/soft/myjar/HiveCode15-1.0-SNAPSHOT.jar;
 *      ② create temporary function getlen as "com.shujia.udf.MyNewUDFDemo";
 *      ③ select getlen("abcd"); 或者 show functions like "*len*";

(2)UDTF: 传入一行参数,之后通过forward传出多行数据

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.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.apache.hadoop.io.Text;

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


/**
 * 需求:
 * 通过wordCount 去实现一个 切分数据,并将一行数据变成多行数据
 * 类似于: explode(split(word,','))    
 * spark,hadoop,Java变成
 *spark
 *hadoop
 *Java
 */
public class MyUDTFDemo extends GenericUDTF {

   //实例化UDTF
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {

        // 获取所有字段的列表
        List<? extends StructField> fieldRefs = argOIs.getAllStructFieldRefs();

        // 判断传入参数的长度
        if (fieldRefs.size() != 2) {
            throw new UDFArgumentLengthException("传入参数长度不对...");
        }

        // 判断传入的数据类型
        // 注意:UDTF是没有自己的类型异常类,可以通过UDF的类型异常类
        for (int i = 0; i < fieldRefs.size(); i++) {
            if (!fieldRefs.get(i).getFieldObjectInspector().getCategory().equals(ObjectInspector.Category.PRIMITIVE)) {
                throw new UDFArgumentTypeException(i, "传入参数类型不对...");
            }
        }

        // 输出数据的字段名称
        ArrayList<String> fieldNames = new ArrayList<String>();
        fieldNames.add("outWord");

        // 输出数据的字段类型
        ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
// 增加数据的数据类型,writableStringObjectInspector表示Hadoop中的writable序列化的String -> Text

        fieldOIs.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
// 增加数据的数据类型 javaStringObjectInspector 表示 输出数据类型为Java中的String类型 具体需要跟ArrayList<Text> lineRes 中的数据类型保存一致

//fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
    }

    /**
     * process:具体的数据处理对象
     *
     * forward中的处理方法:collector.collect(o);  表示通过收集器的收集方法收集一行数据,
     */
    @Override
    public void process(Object[] args) throws HiveException {

        ArrayList<Text> lineRes = new ArrayList<>();

        // 判断数据是否为null 如果不做判断,那么数据中如果有null 那么会直接报空指针异常
        if (args[0] == null) {
            lineRes.add(null);
            forward(lineRes);
        }

        String line = args[0].toString();
        String regex = args[1].toString();
        for (String s : line.split(regex)) {
            lineRes.clear();
            lineRes.add(new Text(s));
            // 提交每行数据
            forward(lineRes);
        }
    }

    @Override
    public void close() throws HiveException {
        System.out.println("Nothing to do...");
    }
}

使用命令:

hive 中的创建语句:
 * ① 添加打包好的jar 至hive lib中 add jar /usr/local/soft/myjar/HiveCode15-1.0-SNAPSHOT.jar;
 * ② create temporary function myudtf as "com.shujia.udf.MyUDTFDemo";
 * ③  select myudf(word,",") from wordcount;

UDTF:

流程:
*      ① 实例化UDFT,并且在实例化方法initialize中去判断传入参数的数据长度 以及 数据类型
*      ② 创建输出字段名称的数组以及字段数据类型的数组
*      ③ process中编辑处理的逻辑
*      ④ 将处理好的数据通过forward方法将数据按行写出
*      ⑤ 将项目打包至Linux中hive中创建临时函数,并使用
*
* 实现过程:
*      创建数据库
*          create database learn4;
*      创建表:
*          create table learn4.movie(json_str String Comment "电影JSON") STORED AS TEXTFILE;
*      上传数据:
*          load data local inpath "/usr/local/soft/hive-3.1.2/data/UDTF.txt" into table learn4.movie;
*      查看数据:
*          select get_json_object(json_str,"$.movie") from learn4.movie;
*
*      上传jar包:
*          add jar /usr/local/soft/myjar/HiveCode15-1.0-SNAPSHOT.jar
*
*      创建临时函数:
*          create temporary function myudtf as "com.shujia.udf.MyUDTFDemo2";
*
*      测试函数:
*          select myudtf(get_json_object(json_str,"$.movie")) from learn4.movie;
/**
 *
 * 需求:
 *      {"movie": [{"movie_name": "肖申克的救赎", "MovieType": "犯罪" }, {"movie_name": "肖申克的救赎", "MovieType": "剧情" }]}
 *      为一行数据,类型为JSON,需要从JSON中取出 movie_name MovieType 两个Key对应的Value值
 *      并且数据输出的格式为:
 *          movie_name      MovieType
 *          肖申克的救赎      犯罪
 *          肖申克的救赎      剧情
 *          ...
 
 */


public class MyUDTFDemo2 extends GenericUDTF {

    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
//        实例化UDFT,并且在实例化方法initialize中去判断传入参数的数据长度 以及 数据类型
        List<? extends StructField> fieldRefs = argOIs.getAllStructFieldRefs();

        if(fieldRefs.size() != 1){
            throw new UDFArgumentLengthException("长度不是1,不符合要求");
        }
        if(!fieldRefs.get(0).getFieldObjectInspector().getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
            throw new UDFArgumentTypeException(0,"数据类型不正确");
        }

//        ② 创建输出字段名称的数组以及字段数据类型的数组
        ArrayList<String> columNames = new ArrayList<>();
        ArrayList<ObjectInspector> columType = new ArrayList<>();

        columNames.add("movie_name");
        columType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        columNames.add("MovieType");
        columType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(columNames, columType);

    }

    @Override
    public void process(Object[] args) throws HiveException {
//        ③ process中编辑处理的逻辑
        String[] outline = new String[2];
        if(args[0] != null){
            JSONArray jsonArray = new JSONArray(args[0].toString());
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                outline[0] = jsonObject.getString("movie_name");
                outline[1] = jsonObject.getString("MovieType");
//                ④ 将处理好的数据通过forward方法将数据按行写出
                forward(outline);
            }
        }else {
            outline[0] = null;
            outline[1] = null;
            forward(outline);
        }


    }

    @Override
    public void close() throws HiveException {

    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值