目录
本篇文章将介绍用户访问session分析-session随机抽取之按时间比例随机抽取算法实现。
分析
1.处理的数据格式 <yyyy-MM-dd_HH,count>,需要将数据格式转化为<yyyy-MM-dd,<HH,count>>。
2.计算100个session在需要抽取的天数中平均抽取的个数n。
3.在每天的session中根据每个小时所占比例随机抽取各个时间段抽取这个n个session。
实现
1.将<yyyy-MM-dd_HH,count>格式的map,转换为<yyyy-MM-dd,<HH,count>>
//将<yyyy-MM-dd_HH,count>格式的map,转换为<yyyy-MM-dd,<HH,count>> Map<String,Map<String,Long>> dateHourCountMap = new HashMap<String,Map<String,Long>>(); for (Map.Entry<String, Long> countEntry : countMap.entrySet()){ String dateHour = countEntry.getKey(); String date = dateHour.split("_")[0]; String hour = dateHour.split("_")[1]; long count = countEntry.getValue(); Map<String,Long> hourCountMap = dateHourCountMap.get(date); if (hourCountMap ==null){ hourCountMap = new HashMap<String,Long>(); dateHourCountMap.put(date,hourCountMap); } dateHourCountMap.put(date,hourCountMap); }
2.总共要抽取100个session,按照天数,进行平分
int extractNumberPerDay = 100 /dateHourCountMap.size();
3.在每天的session中根据每个小时所占比例随机抽取各个时间段抽取这个n个session。
//<date,<hour,(1,3,4,2103)>> Map<String,Map<String, List<Integer>>> dateHourExtractMap = new HashMap<String,Map<String,List<Integer>>>(); Random random = new Random(); for (Map.Entry<String,Map<String,Long>> dateHourCountEntry : dateHourCountMap.entrySet()){ String date = dateHourCountEntry.getKey(); Map<String,Long> hourCountMap = dateHourCountEntry.getValue(); //计算出每天的session总数 long sessionCount = 0L; for (long hourCount : hourCountMap.values()){ sessionCount += hourCount; } Map<String,List<Integer>> hourExtractMap = dateHourExtractMap.get(date); if (hourExtractMap == null){ hourExtractMap = new HashMap<String,List<Integer>>(); dateHourExtractMap.put(date,hourExtractMap); } //遍历每一个小时 for (Map.Entry<String,Long> hourCountEntry : hourCountMap.entrySet()){ String hour = hourCountEntry.getKey(); long count = hourCountEntry.getValue(); // 计算每个小时的session数量,占据当天总session数量的比例,直接乘以每天要抽取的数量 // 就可以计算出,当前小时需要抽取的session数量 int hourExtractNumber = (int)((double)count/(double) sessionCount)*extractNumberPerDay; if (hourExtractNumber > count){ hourExtractNumber = (int)count; } //先获取当前小时的存放随机数的list List<Integer> extractIndexList = hourExtractMap.get(hour); if (extractIndexList == null){ extractIndexList = new ArrayList<Integer>(); hourExtractMap.put(hour,extractIndexList); } //生成上面计算出来的数量的随机数 for (int i = 0; i < hourExtractNumber;i++){ int extractIndex = random.nextInt((int)count); while (extractIndexList.contains(extractIndex)){ extractIndex = random.nextInt((int)count); } extractIndexList.add(extractIndex); } } }
完整代码
UserVisitSessionAnalyzeSpark.java
/** * 随机抽取session * @param sessionid2AggrInfoRDD */ private static void randomExtractSession( JavaPairRDD<String, String> sessionid2AggrInfoRDD) { // 第一步,计算出每天每小时的session数量,获取<yyyy-MM-dd_HH,sessionid>格式的RDD JavaPairRDD<String, String> time2sessionidRDD = sessionid2AggrInfoRDD.mapToPair( new PairFunction<Tuple2<String,String>, String, String>() { private static final long serialVersionUID = 1L; @Override public Tuple2<String, String> call( Tuple2<String, String> tuple) throws Exception { String aggrInfo = tuple._2; String startTime = StringUtils.getFieldFromConcatString( aggrInfo, "\\|", Constants.FIELD_START_TIME); String dateHour = DateUtils.getDateHour(startTime); return new Tuple2<String, String>(dateHour, aggrInfo); } }); /** * 思考一下:这里我们不要着急写大量的代码,做项目的时候,一定要用脑子多思考 * * 每天每小时的session数量,然后计算出每天每小时的session抽取索引,遍历每天每小时session * 首先抽取出的session的聚合数据,写入session_random_extract表 * 所以第一个RDD的value,应该是session聚合数据 * */ // 得到每天每小时的session数量 Map<String, Long> countMap = time2sessionidRDD.countByKey(); //第二步,使用按时间比例随机抽取算法,计算出每天每小时需要抽取session的索引 //将<yyyy-MM-dd_HH,count>格式的map,转换为<yyyy-MM-dd,<HH,count>> Map<String,Map<String,Long>> dateHourCountMap = new HashMap<String,Map<String,Long>>(); for (Map.Entry<String, Long> countEntry : countMap.entrySet()){ String dateHour = countEntry.getKey(); String date = dateHour.split("_")[0]; String hour = dateHour.split("_")[1]; long count = countEntry.getValue(); Map<String,Long> hourCountMap = dateHourCountMap.get(date); if (hourCountMap ==null){ hourCountMap = new HashMap<String,Long>(); dateHourCountMap.put(date,hourCountMap); } dateHourCountMap.put(date,hourCountMap); } //开始实现按时间比例随机抽取算法 //总共要抽取100个session,按照天数,进行平分 int extractNumberPerDay = 100 /dateHourCountMap.size(); //<date,<hour,(1,3,4,2103)>> Map<String,Map<String, List<Integer>>> dateHourExtractMap = new HashMap<String,Map<String,List<Integer>>>(); Random random = new Random(); for (Map.Entry<String,Map<String,Long>> dateHourCountEntry : dateHourCountMap.entrySet()){ String date = dateHourCountEntry.getKey(); Map<String,Long> hourCountMap = dateHourCountEntry.getValue(); //计算出每天的session总数 long sessionCount = 0L; for (long hourCount : hourCountMap.values()){ sessionCount += hourCount; } Map<String,List<Integer>> hourExtractMap = dateHourExtractMap.get(date); if (hourExtractMap == null){ hourExtractMap = new HashMap<String,List<Integer>>(); dateHourExtractMap.put(date,hourExtractMap); } //遍历每一个小时 for (Map.Entry<String,Long> hourCountEntry : hourCountMap.entrySet()){ String hour = hourCountEntry.getKey(); long count = hourCountEntry.getValue(); // 计算每个小时的session数量,占据当天总session数量的比例,直接乘以每天要抽取的数量 // 就可以计算出,当前小时需要抽取的session数量 int hourExtractNumber = (int)((double)count/(double) sessionCount)*extractNumberPerDay; if (hourExtractNumber > count){ hourExtractNumber = (int)count; } //先获取当前小时的存放随机数的list List<Integer> extractIndexList = hourExtractMap.get(hour); if (extractIndexList == null){ extractIndexList = new ArrayList<Integer>(); hourExtractMap.put(hour,extractIndexList); } //生成上面计算出来的数量的随机数 for (int i = 0; i < hourExtractNumber;i++){ int extractIndex = random.nextInt((int)count); while (extractIndexList.contains(extractIndex)){ extractIndex = random.nextInt((int)count); } extractIndexList.add(extractIndex); } } } }