hive自定义UDAF函数 O(n)

hive自定义UDAF函数

1.1需求

根据产品净值得到某个时间区间内的净值最大回撤,即max((Di-Dj)/Di), Di>=Dj; i,j为日期, Di、Dj 为净值 且 j>=i。

以9月1号-9月5号为例,得到max[(9.1-9.1)/9.1,(9.1-9.2)/9.1,(9.2-9.2)/9.1 …(9.4-9.5)/9.5 ,(9.45-9.5)/9.5 ].

1.2 分析

需求较为明晰,我只需要把传入的参数放到list,然后求得最大值即可。

根据Di>Dj,若Di<Dj,得到的结果肯定为负值,这个地方需要处理,即Di-Dj<0时 ,赋值为0.

1.3测试数据

由于该函数没有内部排序,需要把数据按日期排序后使用

prd_id	v_date	v_value
1001	2021-08-12	1.43200
1001	2021-08-22	1.23200
1001	2021-08-23	1.33200
1001	2021-08-25	1.12300
1001	2021-08-27	1.53200
1002	2021-08-17	1.50200
1002	2021-08-21	1.23200
1002	2021-08-24	1.33200
1002	2021-08-25	1.13200
1003	2021-08-12	1.03200
1003	2021-08-17	1.21200
1004	2021-08-12	1.212
1004	2021-08-13	1.415
1004	2021-08-15	1.321
1005	2021-08-22	1.332
1005	2021-08-23	1.332
Time taken: 0.099 seconds, Fetched: 16 row(s)

1.4代码实现

需要继承UDAF类 实现UDAFEvaluator接口。

package com.lpy.udf;

import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;

import java.util.ArrayList;
import java.util.Collections;


/**
 * @author liuser
 * @date 2021/09/10
 */
public class UDAF_BACK extends UDAF {
    public static class AvgState {
		//用于存储回撤值
        private ArrayList<Double> doubles;
        //用于接收最大返回值
        private double max_back ;

    }


    public static class AvgEvaluator implements UDAFEvaluator {
        AvgState state;

        public AvgEvaluator() {
            super();
            state = new AvgState();
            init();
        }


        /**
         * init函数类似于构造函数,用于UDAF的初始化
         */
        public void init() {
            state.doubles = new ArrayList<Double>();
            state.max_back=0.0;
        }

        /**
         * iterate接收传入的参数,并进行内部的轮转。其返回类型为boolean * * @param o * @return
         */

        public boolean iterate(Double o) {
            if (o != null) {
                //初始化map存储 id,date,value
                state.doubles.add(o);
            }
            return true;
        }

        /**
         * terminatePartial无参数,其为iterate函数遍历结束后,返回轮转数据, * terminatePartial类似于hadoop的Combiner * * @return
         */

        public AvgState terminatePartial() {
            // combiner


            return state.doubles == null ? null : state;
        }


        /**
         * merge接收terminatePartial的返回结果,进行数据merge操作,其返回类型为boolean * * @param o * @return
         */

        public boolean merge(AvgState avgState) {
            ArrayList<Double> arrList = new ArrayList<Double>();
            if (avgState != null) {
                Object[] split = avgState.doubles.toArray();
                if (split.length <= 1) {
                    state.max_back = 0.00;
                }else {
                    for (int i = 0; i < split.length; i++) {
                        for (int j = i + 1; j < split.length; j++) {
                            arrList.add((Double.parseDouble(split[i].toString()) - Double.parseDouble(split[j].toString())) / Double.parseDouble(split[i].toString()));
                        }
                    }
                    state.max_back = Collections.max(arrList)<=0 ? 0.0:Collections.max(arrList);
                }
            }
            return true;
        }

        /**
         * terminate返回最终的聚集函数结果 * * @return
         */
        public Double terminate() {
            return state.max_back;
        }
    }

}

1.5 打jar包

根据自己的习惯,使用maven等等

1.6 上传服务器

上传huice-1.0.jar 至 /home/liuser/udf_jar/

1.8 使用udaf函数

hive执行 
hive (default)>add jar /home/liuser/udf_jar/huice-1.0.jar ;

hive (default)>create temporary function huice01 as 'com.lpy.udf.UDAF_BACK';


hive (default)> select prd_id,huice01(v_value) from test group by prd_id ;






1.9 结果展示

prd_id	_c1
1001	0.2157821229050279
1002	0.24633821571238357
1003	0.0
1004	0.06643109540636048
1005	0.0

2.0 相关注解

prd_id=1003时只有一条数据,没有回撤值,此时赋予 0.0

prd_id=1005时有多条数据,但是 Di<Dj, 同样没有回撤值,应赋予0.0。

0924 时间复杂度优化(merge 方法)

由于之前时间复杂度对O(n^2),后续在思考如何进行复杂度优化,经过不断改进,将呈现复杂度降到O(n)。
代码如下。

        public boolean merge(AvgState avgState) {
            double drawdown=0.0;
            ArrayList<Double> drawdowns = new ArrayList<Double>();
            Object[] split = avgState.doubles.toArray();
            Double max_so_far = (Double)split[0];
            for (int i = 0; i < split.length; i++) {
                if (Double.parseDouble(split[i].toString()) > max_so_far) {
                    drawdown=0.0;
                    drawdowns.add(drawdown);
                    max_so_far = Double.parseDouble(split[i].toString());
                }else {
                    drawdown = (max_so_far - Double.parseDouble(split[i].toString())) / max_so_far;
                    drawdowns.add(drawdown);
                }
            }
            state.max_back = Collections.max(drawdowns)<=0 ? 0.0:Collections.max(drawdowns);
            
            return true;
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值