udf/udaf/udtf--自定义函数解决个性化场景

一、了解它们

  • 系统内置函数无法解决实际的业务问题,需要开发者自己编写函数实现自身的业务实现诉求。
  • 应用场景非常多,面临的业务不同导致个性化实现很多,故很需要。

二、udf

udf:用户定义(普通)函数,只对单行数值产生作用

特点:一进一出

实现步骤:(java创建自定义udf类)

1、自定义一个java类

2、继承udf类

3、重写evaluate方法

4、打包类所在项目一个all-in-one(所有依赖)的jar包上传到hive所在机器

5、在hive中执行add jar操作,将jar加载到classpath中

6、在hive中创建模板函数,使得可以像使用内嵌函数一样使用这个函数

案例如下:

    /**
     * @function 自定义UDF统计最小值
     *
     */
    public class Min extends UDF {
 
        public Double evaluate(Double a, Double b) {
 
            if (a == null)
                a = 0.0;
            if (b == null)
                b = 0.0;
            if (a >= b) {
                return b;
            } else {
                return a;
            }
        }
    }

三、udaf

udaf:用户定义聚合函数,可对多行数据产生作用;等同与SQL中常用的SUM(),AVG(),也是聚合函数;

特点:多进一出

实现步骤:

1、自定义一个java类

2、继承UDAF类

3、内部定义一个静态类,实现UDAF Evalutor接口

4、实现方法init,iterate,teminatePartial,merge,terminate五个方法,见下图

5、在hive中执行add jar操作,将jar加载到classpath中

6、在hive中创建模板函数,使得可以像使用内嵌函数一样使用这个函数

案例如下:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.log4j.Logger;
/**
* 实现多条数据合并成一条数据
*/
// 主类继承UDAF
public class StudentScoreAggUDAF extends UDAF {
    // 日志对象初始化
    public static Logger logger = Logger.getLogger(StudentScoreAggUDAF.class);
    // 静态类实现UDAFEvaluator
    public static class Evaluator implements UDAFEvaluator {
        // 设置成员变量,存储每个统计范围内的总记录数
        private Map<String, String> courseScoreMap;

        //初始化函数,map和reduce均会执行该函数,起到初始化所需要的变量的作用
        public Evaluator() {
            init();
        }
        // 初始化函数间传递的中间变量
        public void init() {
            courseScoreMap = new HashMap<String, String>();
        }

         //map阶段,返回值为boolean类型,当为true则程序继续执行,当为false则程序退出  
        public boolean iterate(String course, String score) {
            if (course == null || score == null) {
                return true;
            }
            courseScoreMap.put(course, score);
            return true;
        }
         /**
         * 类似于combiner,在map范围内做部分聚合,将结果传给merge函数中的形参mapOutput  
         * 如果需要聚合,则对iterator返回的结果处理,否则直接返回iterator的结果即可
         */
        public Map<String, String> terminatePartial() {
            return courseScoreMap;
        }
         // reduce 阶段,用于逐个迭代处理map当中每个不同key对应的 terminatePartial的结果
        public boolean merge(Map<String, String> mapOutput) {
            this.courseScoreMap.putAll(mapOutput);
            return true;
        }
        // 处理merge计算完成后的结果,即对merge完成后的结果做最后的业务处理
        public String terminate() {
            return courseScoreMap.toString();
        }
    }
}

四、udtf

udtf:用户定义表生成函数,用来解决输入一行输出多行;往往被lateral view explode()+udf等替代实现,比直接用udtf会更简单、直接一些

特点:一进多出

实现步骤:

1、自定义一个java类

2、继承GenericUDTF类1

3、实现initialize(手动覆盖)、process(必须实现)、close(必须实现)方法,手动覆盖如下

public StructObjectInspector initialize(StructObjectInspector argOIs)
  throws UDFArgumentException { }

lateral view explode:

select user_id -- 原字段
      ,user_layer -- 原字段
      ,ordr_id -- 拆分字段
from A
lateral view explode(ordr_set)tmp1 as ordr_id

使用lateral view的时候需要注意的几点:

1. lateral view的位置是from后where条件前;

2. 生成的虚拟表的表名不可省略;

3. from后可带多个lateral view;

4. 如果要拆分的字段有null值,需要使用lateral view outer 替代,避免数据缺失,这个坑我在工作中踩过!

97在职大数据,开发看心情整理一些干货,欢迎关注和分享!欢迎探讨学习!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值