大数据项目实战之十五:15.session聚合统计之自定义Accumulator

Accumulator传统的实现方式,有如下缺点:

1.在写后面的累加代码的时候,比如找到了一个4s~6s的区间的session,但是在代码里面不小心累加到7s~9s里面去了;

2.当后期项目出现一些逻辑上的变更,比如说,session数量的计算逻辑,要改变,就得更改所有Accumulator对应的代码;或者说,又要增加几个范围,那么又要增加多个Accumulator,并且修改对应的累加代码;维护成本,相当之高(甚至可能,修改一个小功能,或者增加一个小功能,耗费的时间,比做一个新项目还要多;甚至于还修改出了bug,那就耗费更多的时间)

所以,我们这里的设计,不采用传统的方式,用十几个甚至二十个Accumulator,因为维护成本太高!

我们的实现思路是,自定义一个Accumulator,实现较为复杂的计算逻辑:一个Accumulator维护了所有范围区间的数量的统计逻辑,实现低耦合.如果说,session数量计算逻辑要改变,那么不用变更session遍历的相关的代码,只要维护一个Accumulator里面的代码即可; 如果计算逻辑后期变更,或者加了几个范围,那么也很方便,不用多加好几个Accumulator,去修改大量的代码;只要维护一个Accumulator里面的代码即可, 维护成本,大大降低

使用自定义Accumulator,大家就可以任意的实现自己的复杂分布式计算的逻辑.如果说,task在分布式运行,进行复杂计算逻辑,那么是很难实现的(借助于redis,维护中间状态,借助于zookeeper去实现分布式锁),但是,使用自定义Accumulator,可以更方便进行中间状态的维护,而且不用担心并发和锁的问题

使用自己定义的一些数据格式,比如String,甚至说,我们可以自己定义model(必须可序列化),然后基于这种特殊的数据格式,可以实现复杂的分布式的计算逻辑;各个task,分布式在运行,可以根据你的需求,task给Accumulator传入不同的值,根据不同的值,去做复杂的逻辑,比如更新Redis,HBASE,MySQL

/**
 * session聚合统计之自定义Accumulator
 */
public class SessionAggrStatAccumulator implements AccumulatorParam<String> {

    private static final long serialVersionUID = 6311074555136039130L;

    /**
     * addInPlace和addAccumulator可以理解为是一样的
     * 第一个参数,就是我们初始化的那个连接串
     * 第二个参数,就是我们在遍历session的时候,判断出某个session对应的区间,然后会用Constants.TIME_PERIOD_1s_3s
     * 我们要做的就是:在第一个参数中,找到第二个参数对应的value,然后更新回第一个参数的连接串中去
     */


    @Override
    public String addAccumulator(String t1, String t2) {
        return add(t1, t2);
    }

    @Override
    public String addInPlace(String r1, String r2) {
        return add(r1, r2);
    }

    /**
     * zero方法,主要用于数据的初始化
     * 那么在这个方法中返回一个值,就是在初始化中,所有范围区间的数量,都是0
     * 各个范围区间的统计数量的拼接,还是采用key=value|key=value的连接串格式
     *
     * @param v
     * @return
     */
    @Override
    public String zero(String v) {
        return Constants.SESSION_COUNT + "=0|"
                + Constants.TIME_PERIOD_1s_3s + "=0|"
                + Constants.TIME_PERIOD_4s_6s + "=0|"
                + Constants.TIME_PERIOD_7s_9s + "=0|"
                + Constants.TIME_PERIOD_10s_30s + "=0|"
                + Constants.TIME_PERIOD_30s_60s + "=0|"
                + Constants.TIME_PERIOD_1m_3m + "=0|"
                + Constants.TIME_PERIOD_3m_10m + "=0|"
                + Constants.TIME_PERIOD_10m_30m + "=0|"
                + Constants.TIME_PERIOD_30m + "=0|"
                + Constants.STEP_PERIOD_1_3 + "=0|"
                + Constants.STEP_PERIOD_4_6 + "=0|"
                + Constants.STEP_PERIOD_7_9 + "=0|"
                + Constants.STEP_PERIOD_10_30 + "=0|"
                + Constants.STEP_PERIOD_30_60 + "=0|"
                + Constants.STEP_PERIOD_60 + "=0";
    }


    /**
     * session统计计算逻辑
     *
     * @param v1 连接串
     * @param v2 范围区间
     * @return 更新以后的连接串
     */
    private String add(String v1, String v2) {
        //校验,v1为空的话,直接返回v2
        if (StringUtils.isEmpty(v1)) {
            return v2;
        }

        //使用StringUtils工具类,从v1中提取v2对应的value值,并累加1
        String oldValue = StringUtils.getFieldFromConcatString(v1, "//|", v2);
        if (oldValue != null) {
            //将范围区间的原有值,累加1
            int newValue = Integer.valueOf(oldValue) + 1;
            // 使用StringUtils工具类,将v1中,v2对应的值,设置成新的累加后的值
            return StringUtils.setFieldInConcatString(v1, "//|", v2, String.valueOf(newValue));
        }


        return v1;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值