spark 大型项目实战(十七):用户访问session分析(十七) -- session 聚合之自定义Accumulator

文章地址:http://www.haha174.top/article/details/253747
源码:https://github.com/haha174/spark-session.git
session聚合统计:

统计出来之前通过条件过滤的session,访问时长在0s~3s的session的数量,占总session数量的比例;4s~6s。。。。;
访问步长在1~3的session的数量,占总session数量的比例;4~6。。。;

Accumulator 1s_3s = sc.accumulator(0L);
。。
。。
。。
十几个Accumulator

可以对过滤以后的session,调用foreach也可以,遍历所有session;计算每个session的访问时长和访问步长;
访问时长:把session的最后一个action的时间,减去第一个action的时间
访问步长:session的action数量
计算出访问时长和访问步长以后,根据对应的区间,找到对应的Accumulator,1s_3s.add(1L)
同时每遍历一个session,就可以给总session数量对应的Accumulator,加1
最后用各个区间的session数量,除以总session数量,就可以计算出各个区间的占比了

这种传统的实现方式,有什么不好???

最大的不好,就是Accumulator太多了,不便于维护
首先第一,很有可能,在写后面的累加代码的时候,比如找到了一个4s6s的区间的session,但是却代码里面不小心,累加到7s9s里面去了;
第二,当后期,项目如果要出现一些逻辑上的变更,比如说,session数量的计算逻辑,要改变,就得更改所有Accumulator对应的代码;或者说,又要增加几个范围,那么又要增加多个Accumulator,并且修改对应的累加代码;维护成本,相当之高(甚至可能,修改一个小功能,或者增加一个小功能,耗费的时间,比做一个新项目还要多;甚至于,还修改出了bug,那就耗费更多的时间)

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

自定义Accumulator,也是Spark Core中,属于比较高端的一个技术
使用自定义Accumulator,大家就可以任意的实现自己的复杂分布式计算的逻辑
如果说,你的task,分布式,进行复杂计算逻辑,那么是很难实现的(借助于redis,维护中间状态,借助于zookeeper去实现分布式锁)
但是,使用自定义Accumulator,可以更方便进行中间状态的维护,而且不用担心并发和锁的问题
下面给出代码

/**
 * session聚合统计Accumulator
 * 
 * 大家可以看到
 * 其实使用自己定义的一些数据格式,比如String,甚至说,我们可以自己定义model,自己定义的类(必须可序列化)
 * 然后呢,可以基于这种特殊的数据格式,可以实现自己复杂的分布式的计算逻辑
 * 各个task,分布式在运行,可以根据你的需求,task给Accumulator传入不同的值
 * 根据不同的值,去做复杂的逻辑
 * 
 * 
 * @author wchen129
 *
 */
public class SessionAggrStatAccumulator implements AccumulatorParam<String> {

	private static final long serialVersionUID = 6311074555136039130L;
	
	/**
	 * zero方法,其实主要用于数据的初始化
	 * 那么,我们这里,就返回一个值,就是初始化中,所有范围区间的数量,都是0
	 * 各个范围区间的统计数量的拼接,还是采用一如既往的key=value|key=value的连接串的格式
	 */
	@Override
	public String zero(String v) {
		return Constants.SESSION_PROJECT.SESSION_COUNT + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_1s_3s + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_4s_6s + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_7s_9s + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_10s_30s + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_30s_60s + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_1m_3m + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_3m_10m + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_10m_30m + "=0|"
				+ Constants.SESSION_PROJECT.TIME_PERIOD_30m + "=0|"
				+ Constants.SESSION_PROJECT.STEP_PERIOD_1_3 + "=0|"
				+ Constants.SESSION_PROJECT.STEP_PERIOD_4_6 + "=0|"
				+ Constants.SESSION_PROJECT.STEP_PERIOD_7_9 + "=0|"
				+ Constants.SESSION_PROJECT.STEP_PERIOD_10_30 + "=0|"
				+ Constants.SESSION_PROJECT.STEP_PERIOD_30_60 + "=0|"
				+ Constants.SESSION_PROJECT.STEP_PERIOD_60 + "=0";
	}
	
	/**
	 * addInPlace和addAccumulator
	 * 可以理解为是一样的
	 * 
	 * 这两个方法,其实主要就是实现,v1可能就是我们初始化的那个连接串
	 * v2,就是我们在遍历session的时候,判断出某个session对应的区间,然后会用Constants.SESSION_PROJECT.TIME_PERIOD_1s_3s
	 * 所以,我们,要做的事情就是
	 * 在v1中,找到v2对应的value,累加1,然后再更新回连接串里面去
	 * 
	 */
	@Override
	public String addInPlace(String v1, String v2) {
		return add(v1, v2);
	}
	
	@Override
	public String addAccumulator(String v1, String v2) {
		return add(v1, v2);
	}  
	
	/**
	 * session统计计算逻辑
	 * @param v1 连接串
	 * @param v2 范围区间
	 * @return 更新以后的连接串
	 */
	private String add(String v1, String v2) {
		// 校验:v1为空的话,直接返回v2
		if(StringUtils.isEmpty(v1)) {
			return v2;
		}
		
		// 使用StringUtils工具类,从v1中,提取v2对应的值,并累加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;
	}
	
}

欢迎关注,更多惊喜等着你

这里写图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值