小白学hadoop日记day13——hive自定义函数

场景:
hive的内置函数满足不了所有的业务需求。
hive提供很多的模块可以自定义功能,比如:自定义函数、serde、输入输出格式等。
hive提供的自定义函数:
UDF:user defined function,用户自定函数,一行输入一行输出。类似于普通函数,如size,length
UDAF:user defined aggregate function,用户自定义聚合函数,多行输入一行输出。类似sum
UDTF:user defined table-gernarate function,用户自定义表生成函数,一行输入多行输出。类似炸裂
UDF案例
定义UDF函数要注意下面几点:
1. 继承`org.apache.hadoop.hive.ql.exec.UDF`
2. 重写`evaluate`(),这个方法不是由接口定义的,因为它可接受的参数的个数,数据类型都是不确定的。Hive会检查UDF,看能否找到和函数调用相匹配的evaluate()方法。
3、`evaluate`()允许重载。

UDF案例

pom.xml

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

FirstFun

package com.al.hive;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDF;
/**
 * 第一个自定义函数.
 * 做两个数的拼接
 */
public class FirstFun extends UDF {
   //重写evaluate,名字不能错
    //String:方法返回值类型
    //String a,String b  :方法的输入参数和类型
    public String evaluate(String a,String b){
       if(StringUtils.isEmpty(a)){
           return null;
        }
        if(StringUtils.isEmpty(b)){
            return null;
        }
        //数据正常
        return a+"_"+b;
    }
    //重载
    public String evaluate(String a){
        if(StringUtils.isEmpty(a)){
            return null;
        }
        //数据正常
        return a;
    }
}

​

这种加载只对本session有效

# 将编写的udf的jar包上传到服务器上.
# 并且将jar包添加到hive的class path中
# 进入到hive客户端,执行下面命令
hive> add jar /home/qf-2102-1.0.jar;
-- 创建一个临时函数名,要跟上面hive在同一个session里面:
hive> create temporary function myConcat as 'com.al.hive.FirstFun';
-- 检查函数是否创建成功
hive> show functions;
-- 查看函数使用方法
hive> desc function myconcat;
-- 测试功能
hive (test)>select myconcat('cc','ad');
OK
cc_ad
Time taken: 0.806 seconds, Fetched: 1 row(s)
hive (test)> select myconcat('cc');
OK
cc
Time taken: 0.09 seconds, Fetched: 1 row(s)
hive (test)> select myconcat('cc','');
OK
NULL

-- 删除函数 
hive> drop temporary function if exists myconcat;

配置文件加载

通过配置文件方式这种只要用hive命令行启动都会加载函数

# 1、将编写的udf的jar包上传到服务器上
# 2、在hive的安装目录的bin目录下创建一个配置文件,文件名:.hiverc
[root@01 hive]#  vi ./.hiverc
add jar /home/qf-2102-1.0.jar;
create temporary function myConcat as 'com.al.hive.FirstFun';
3、启动hive
 [root@01 hive]# hive
hive> select myconcat('cc','ad');

注册永久函数

将jar包上传到hdfs的目录中。

# 1、将编写的udf的jar包上传到hdfs上
[root@hadoop01 ~]# hdfs dfs -mkdir /auxjars
[root@hadoop01 ~]# hdfs dfs -put /home/qf-2102-1.0.jar /auxjars
create function test.myConcat as 'com.al.hive.FirstFun' using jar 'hdfs://hadoop01:9000/auxjars/qf-2102-1.0.jar';
3、启动hive
 [root@q01 hive]# hive
hive> select myConcat('cc','ad');
Added [/tmp/bc4a1229-2354-4ce5-ad8c-24cdf9df7a1f_resources/qf-2102-1.0.jar] to class path
Added resources: [hdfs://hadoop01:9000/auxjars/qf-2102-1.0.jar]
OK
cc_ad

UDTF案例
UDTF是一对多的输入输出,实现UDTF需要完成下面步骤
    继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
    重写initlizer()、process()、close()。
执行流程如下:
    UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)。
    初始化完成后,会调用process方法,真正的处理过程在process函数中,在process中,每一次forward()调用产生一行;如果产生多列可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数。
    最后close()方法调用,对需要清理的方法进行清理。

/*把"k1:v1;k2:v2;k3:v3"类似的的字符串解析成每一行多行,每一行按照key:value格式输出
kv2clo("k1:v1;k2:v2;k3:v3")
k1:v1
k2:v2
k3:v3
*/
package com.al.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.ql.udf.generic.GenericUDTFExplode;
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;
import java.util.List;

/**
 * 表生成函数
 */
public class MyUDTF extends GenericUDTF {

    //在initializez中初始化要输出字段的名称和类型
    @Override
    public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
        //定义要输出列的名字的List,并且添加要输出的列名
        List<String> structFieldNames = new ArrayList<String>();
        structFieldNames.add("key");
        structFieldNames.add("value");

        //定义要输出列的类型的List,并且添加要输出列的类型

        List<ObjectInspector> objectInspectorList = new ArrayList<ObjectInspector>();

      objectInspectorList.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        objectInspectorList.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        //定义返回的schema
        return ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, objectInspectorList);
    }
    /**
     * 核心处理方法
     * @param objects
     * @throws HiveException
     */
    public void process(Object[] objects) throws HiveException {
        //得到第一个参数,转化为字符串,类似于->  name:zhang;age:30;address:shenzhen
        String insputString = objects[0].toString();
        //把上述例子字符串按照分号;切分为数组
        String[] split = insputString.split(";");
        //s=name:zhang
        for (String s : split) {
            //把每个切分后的key value分开
            String[] kvArray = s.split(":");
            //如果产生多列可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数。
           forward(kvArray);
        }
    }

    //关闭对象
    public void close() throws HiveException {

    }
}

UDAF案例
 用户自定义聚合函数。user defined aggregate function。多对一的输入输出 count sum max。定义一个UDAF需要如下步骤:
    UDF自定义函数必须是org.apache.hadoop.hive.ql.exec.UDAF的子类,并且包含一个有多个嵌套的的实现了org.apache.hadoop.hive.ql.exec.UDAFEvaluator的静态类。
    函数类需要继承UDAF类,内部类Evaluator实UDAFEvaluator接口。
    Evaluator需要实现 init、iterate、terminatePartial、merge、terminate这几个函数

这几个函数作用如下:
函数                                  说明
init                                   实现接口UDAFEvaluator的init函数
iterate                              每次对一个新值进行聚集计算都会调用,计算函数要根据计算的结果更新其内部状 态,map端调用
terminatePartial              无参数,其为iterate函数轮转结束后,返回轮转数据,,map端调用
merge                接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean。
terminate                        返回最终的聚集函数结果。 在reducer端调用

//计算一组整数的最大值
package com.al.hive;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.io.IntWritable;
//注解方法的描述,,desc function name

@Description(value = "findmax(col)",name = "findmax",extended = "this is find max function")
public class MyUDAF extends UDAF {
    //UDAF要求 并且包含一个或者多个嵌套的的实现了
    // org.apache.hadoop.hive.ql.exec.UDAFEvaluator的静态类。
    public static class MaxnumIntUDAFEvaluator implements UDAFEvaluator {
        //在静态类内部定义一个返回值,作为当前UDAF最后的唯一返回值,因为返回值要在hive调用,所以必须要使用序列化类型
        private IntWritable result;
        /**
         * 在初始化是把返回值设为null,避免和上次调用时混淆
         */
        public void init() {
            result=null;
        }
        /*
        A 3
        A 1
        V 5
        A 5
        ite(1,1,1)
         */
        //定义一个函数iterate用来处理遍历多行时,每行值传进来是调用的函数
        public boolean iterate(IntWritable value) {
            //把遍历每行的值value传入,和result比较,如果比result大,那么result就设置为value,否则result不变
            if (value == null) {
                return true;
            }
            //如果是第一行数据,那么直接给result赋值为第一行数据
            if (result == null) {
                result = new IntWritable(value.get());
            } else {
                //给result赋值result和value之间的最大值
                result.set(Math.max(result.get(),value.get()));
            }
            return true;
        }
        /**
         * 在map端进行并行执行后的结果
         * @return
         */
        public IntWritable terminatePartial() {
           return result;
        }
        /**
         * 接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean。
         * @param other
         * @return
         */

        public boolean merge(IntWritable other) {

            return iterate(other);
        }

        /**
         * 将最终的结果返回为Hive
         * @return
         */
        public IntWritable terminate() {
            return result;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值