hive的自定义函数

一、自定义函数的实现方式

1.创建临时函数

   (1)创建maven项目,并加入依赖

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

  (2)编写函数的实现逻辑的代码

(3)打成jar包并上传至Linux虚拟机(带依赖打包)

(4)在hive shell中,使用 add jar 路径将jar包作为资源添加到hive环境中

        add jar jar包路径;

(5)使用jar包资源注册一个临时函数,fxxx1是函数名,'MyUDF'是主类名

        create temporary function fxxx1 as 'MyUDF';

(6)可以使用show functions 查看函数是否被创建

2.创建永久函数

(1)将jar上传HDFS:

          hadoop fs -put jar包路径

(2)在hive命令行中创建永久函数:

         create function 函数名 as '主类名路径' using jar 'hdfs:/bigdata29/jars/hive-1.0-jar-with-dependencies.jar(hdfs上的jar包路径)';

(3)删除永久函数

         drop function 函数名;

3.实现UDF自定义函数

(旧版本方式):

import org.apache.hadoop.hive.ql.exec.UDF;

/*
    旧版本实现UDF自定义函数的时候,需要将自己的类继承UDF类
 */
public class MyUDFDemo1 extends UDF {
    /*
        实现evaluate函数
        将来hive调用自定义函数的时候,实际上调用的是该类中的evaluate函数
        evaluate函数的参数就是将来sql语句传入的列值
        evaluate函数的返回值就是自定义函数的返回值

        需求:传入一个字符串,返回一个新的字符串
        举例:SMITH --> 数加:SMITH

        select xxx(ename) from emp;
     */
    public String evaluate(String str) {
        // 返回字符串前缀"数加:"加上输入参数str
        return "数加:" + str;
    }

    public String evaluate(int number) {
        // 返回字符串前缀"数加:"加上输入参数str
        if(number>=90 && number<=100){
            return "优秀";
        }else if(number>=70 && number<90){
            return "良好";
        }else if(number>=60){
            return "及格";
        }else {
            return "不及格";
        }
    }

}

(新版本方式):

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
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.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;

public class MyGenericUDFDemo1 extends GenericUDF {

    /*
        这个方法主要是对自定义的UDF函数进行初始化,目的是指定调用完函数返回的值的类型
        需求:传入一个字符串,返回一个新的字符串
        举例:SMITH --> 数加:SMITH
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        //使用PrimitiveObjectInspectorFactory工厂类,获取String类型的ObjectInspector
        return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
    }

    /*
        该方法是自定义UDF的核心方法,目的是实现自定义UDF的逻辑
        是在initialize方法之后执行的

        arguments将来会有多个参数,但是UDF函数只有一个参数,所以arguments[0]就是传入的第一个参数
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException { //xiaohu("smith")  xiaohu(60)
        String output = ""; 
        //arguments[0]获取第一个参数值,通过get()方法获取其中的参数具体值
        Object o = arguments[0].get(); // Object o = 100
        if (o != null) { //如果将来调用自定义函数不传值的话,则o为null,需要加入判断,防止空指针异常
            if (o instanceof Text) {
                output = "数加:" + o;
            }else if(o instanceof IntWritable){ // hive中传入整数的时候,底层默认是IntWritable类型的
                int score = ((IntWritable) o).get();
                if(score>=90 && score<=100){
                    output = "优秀";
                }else if(score>=70 && score<90){
                    output = "良好";
                }else if(score>=60){
                    output = "及格";
                }else {
                    output = "不及格";
                }
            }
        }
        return output;
    }

    @Override
    public String getDisplayString(String[] children) {
        return "这是我们自己使用新版本写法自定义的UDF函数";
    }
}

4.实现UDTF自定义函数

案例1:

将一行数据  M1001#xiaohu#S324231212,lkd#M1002#S2543412432,S21312312412#M1003#bfy

变为以下形式(三行):

1001 xiaohu 324231212

1002 lkd 2543412432

1003 bfy 21312312412

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

/*
    编写UDTF的类需要自己自定义的类继承自GenericUDTF
 */
public class MyUDTFDemo1 extends GenericUDTF {

    /*
        public StructObjectInspector initialize(StructObjectInspector argOIs)
        指定输出的列的名称以及列的类型
        M1001#xiaohu#S324231212,sp#M1002#S2543412432,S21312312412#M1003#dyj

        1001 xiaohu 324231212
     */
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //创建一个List集合存储结果列的名字
        ArrayList<String> colNames = new ArrayList<>();
        //创建一个集合存储每一列的数据类型
        ArrayList<ObjectInspector> colTypes = new ArrayList<>();

        //向集合中添加元素,设置列的名字以及类型
        colNames.add("id");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        colNames.add("name");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        colNames.add("cardId");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        //返回一个对象,该对象封装了列的名字以及列的类型
        return ObjectInspectorFactory.getStandardStructObjectInspector(colNames, colTypes);
    }

    /*
        process方法主要是在调用函数的时候,底层会进行调用处理传入的列数据

        M1001#xiaohu#S324231212,sp#M1002#S2543412432,S21312312412#M1003#dyj
        args: 接收函数调用时传入的列数据,从索引0开始
     */
    @Override
    public void process(Object[] args) throws HiveException {

        //创建一个数组,存储每一列的数据
        //因为结果一行数据中有3列,需要创建一个长度为3的数组,用来存储我们处理过的一行三列数据
        String[] rows = new String[3];

        //args[0]是传入的第一个列数据
        String col = args[0].toString();
        String[] infos = col.split(",");
        //遍历切分后的数组,得到每一个用户信息
        for (String info : infos) {
            String[] strings = info.split("#");
            for (String i : strings) {
                if(i.startsWith("M")){ // M1001
                    rows[0] = i.substring(1);
                }else if(i.startsWith("S")){
                    rows[2] = i.substring(1);
                }else {
                    rows[1] = i;
                }
            }
            //forward(Object o) 调用概述方法,将输出的一行数据,封装成一个数组,传入到forward方法中,给hive后续处理
            forward(rows);
        }
    }

    @Override
    public void close() throws HiveException {
        //这里一般是用作释放在initialize方法中创建的资源

    }
}

案例二:

字段:id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12 共13列

数据:

a,1,2,3,4,5,6,7,8,9,10,11,12

b,11,12,13,14,15,16,17,18,19,20,21,22

c,21,22,23,24,25,26,27,28,29,30,31,32

转成3列:id,hours,value

例如:

a,1,2,3,4,5,6,7,8,9,10,11,12

a,0时,1

a,2时,2

a,4时,3

a,6时,4

......

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

/*
    输入:a,1,2,3,4,5,6,7,8,9,10,11,12
    输出:
        a 0时 1
        a 2时 2
        a 4时 3
        ..
        a 24时 12

 */
public class MyUDTFDemo3 extends GenericUDTF {
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //创建一个List集合存储结果列的名字
        ArrayList<String> colNames = new ArrayList<>();
        //创建一个集合存储每一列的数据类型
        ArrayList<ObjectInspector> colTypes = new ArrayList<>();

        //向集合中添加元素,设置列的名字以及类型
        colNames.add("id");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        colNames.add("time");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        colNames.add("value");
        colTypes.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        //返回一个对象,该对象封装了列的名字以及列的类型
        return ObjectInspectorFactory.getStandardStructObjectInspector(colNames, colTypes);
    }


    /*
        输入:a,1,2,3,4,5,6,7,8,9,10,11,12
        输出:
            a 0时 1
            a 2时 2
            a 4时 3
            ..
            a 24时 12

     */
    @Override
    public void process(Object[] args) throws HiveException { //作用在每一行上的
        //创建一个数组,存储一行三列的数据
        String[] rows = new String[3];

        //因为接收了13列的数据,args的长度是13 索引最大值是12
        //第一列是监测点编号
        String id = args[0].toString();
        rows[0] = id;
        for (int i = 1, j = 0; i < args.length; i++, j += 2) {
            rows[1] = j + "时";
            rows[2] = args[i].toString();

            forward(rows);
        }
    }

    @Override
    public void close() throws HiveException {

    }
}
  • 31
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值