按时间比例随机抽取session

22 篇文章 2 订阅

每一次执行用户访问session分析模块,要抽取出100个session

session随机抽取:按每天的每个小时的session数量,占当天session总数的比例,乘以每天要抽取的session数量,计算出每个小时要抽取的session数量;然后呢,在每天每小时的session中,随机抽取出之前计算出来的数量的session。

举例:10000个session,抽取100个session;0点~1点之间,有2000个session,占总session的比例就是0.2;按照比例,0点~1点需要抽取出来的session数量是100 * 0.2 = 20个;在0点~点的2000个session中,随机抽取出来20个session。

1.1、我们之前有什么数据:session粒度的聚合数据(计算出来session的start_timesession聚合数据进行映射,将每个session发生的yyyy-MM-dd_HH(start_time)作为key,value就是聚合的数据

    //<yyyy-MM-dd_HH, aggrInfo>
        JavaPairRDD<String, String> session2TimeRDD = filteredSessionid2AggrInfoRDD.mapToPair(new PairFunction<Tuple2<String,String>, String, String>() {

            @Override
            public Tuple2<String, String> call(Tuple2<String, String> t)
                    throws Exception {
                String aggrInfo = t._2;
                //获取session的开始时间
                String startTime =  StringUtils.getFieldFromConcatString(
                        aggrInfo, "\\|", Constants.FIELD_START_TIME);
                String dateHour = DateUtils.getDateHour(startTime);

                return new Tuple2<String, String>(dateHour, aggrInfo);
            }
        });

1.2对上述数据,使用countByKey算子,就可以获取到每天每小时的session数量

        //统计出每小时的session量
        Map<String, Object> countMap = session2TimeRDD.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, Object> countEntry : countMap.entrySet()) {
            String dateHour = countEntry.getKey();
            String date = dateHour.split("_")[0];
            String hour = dateHour.split("_")[1];  

            long count = Long.valueOf(String.valueOf(countEntry.getValue()));  

            Map<String, Long> hourCountMap = dateHourCountMap.get(date);
            if(hourCountMap == null) {
                hourCountMap = new HashMap<String, Long>();
                dateHourCountMap.put(date, hourCountMap);
            }

            hourCountMap.put(hour, count);
        }
        System.out.println(dateHourCountMap);

1.3、(按时间比例随机抽取算法)每天每小时有多少session,

1.3.1、根据这个数量计算出每天每小时的session占比,
1.3.2、按照占比,需要抽取多少session,可以计算出每个小时内,从0~session数量之间的范围中,获取指定抽取数量个随机数,作为随机抽取的索引

            // 开始实现我们的按时间比例随机抽取算法

            // 总共要抽取100个session,先按照天数,进行平分
            int extractNumberPerDay = 100 / dateHourCountMap.size();

            // <date,<hour,(3,5,20,102)>>  
            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数量的比例,直接乘以每天要抽取的数量
                    // 就可以计算出,当前小时需要抽取的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);
                    }
                }
                //00=[11, 40, 18, 41, 36] 每小时抽取的session索引标号
                System.out.println(hourExtractMap);
            }

1.4、把之前转换后的session数据(以yyyy-MM-dd_HH作为key),执行groupByKey算子;然后可以遍历每天每小时的session,遍历时,遇到之前计算出来的要抽取的索引,即将session抽取出来;抽取出来的session,直接写入MySQL数据库

    /**
         *遍历每天每小时的session,然后根据随机索引进行抽取
         */
        // 执行groupByKey算子进行分组,得到<dateHour,(aggrInfo)>  
        JavaPairRDD<String, Iterable<String>> sessions2TimeRDD = session2TimeRDD.groupByKey();

        JavaPairRDD<String, String> extractSessionidsRDD = sessions2TimeRDD.flatMapToPair(new PairFlatMapFunction<Tuple2<String,Iterable<String>>, String, String>() {

            @Override
            public Iterable<Tuple2<String, String>> call(Tuple2<String, Iterable<String>> tuple) throws Exception {
                //返回结果
                List<Tuple2<String, String>> extractSessionids = 
                        new ArrayList<Tuple2<String, String>>();

                String dateHour = tuple._1;
                String date = dateHour.split("_")[0];
                String hour = dateHour.split("_")[1];
                //该组数据
                Iterator<String> sessionsIt = tuple._2.iterator();
                //指定小时抽取session的索引列表
                List<Integer> extractIndexList = dateHourExtractMap.get(date).get(hour);  

                ISessionRandomExtractDAO sessionRandomExtractDAO = 
                        DAOFactory.getSessionRandomExtractDAO();

                //遍历一小时的数据
                int index = 0;
                while(sessionsIt.hasNext()) {
                    String sessionAggrInfo = sessionsIt.next();
                    if(extractIndexList.contains(index)){
                        String sessionid = StringUtils.getFieldFromConcatString(
                                sessionAggrInfo, "\\|", Constants.FIELD_SESSION_ID);

                        extractSessionids.add(new Tuple2<String, String>(sessionid, sessionid));


                        // 将数据写入MySQL
                        System.out.println("insert into mysql>"+sessionid);
                        SessionRandomExtract sessionRandomExtract = new SessionRandomExtract();
                        sessionRandomExtract.setTaskid(1);  
                        sessionRandomExtract.setSessionid(sessionid);  
                        sessionRandomExtract.setStartTime(StringUtils.getFieldFromConcatString(
                                sessionAggrInfo, "\\|", Constants.FIELD_START_TIME));  
                        sessionRandomExtract.setSearchKeywords(StringUtils.getFieldFromConcatString(
                                sessionAggrInfo, "\\|", Constants.FIELD_SEARCH_KEYWORDS));
                        sessionRandomExtract.setClickCategoryIds(StringUtils.getFieldFromConcatString(
                                sessionAggrInfo, "\\|", Constants.FIELD_CLICK_CATEGORY_IDS));

                        sessionRandomExtractDAO.insert(sessionRandomExtract);  
                    }
                    index++;
                }
                return extractSessionids;
            }

        });

经过上一步获取到抽取的sessionid, 只要将该RDD与聚合数据RDD进行join, 获取就是指定sessionid的数据。


        /**
         * 第四步:获取抽取出来的session的明细数据
         */
        JavaPairRDD<String, Tuple2<String, Row>> extractSessionDetailRDD =
                extractSessionidsRDD.join(sessionid2actionRDD);
        extractSessionDetailRDD.foreach(new VoidFunction<Tuple2<String,Tuple2<String,Row>>>() {  

            private static final long serialVersionUID = 1L;

            @Override
            public void call(Tuple2<String, Tuple2<String, Row>> tuple) throws Exception {
                Row row = tuple._2._2;

                SessionDetail sessionDetail = new SessionDetail();
                sessionDetail.setTaskid(1);  
                sessionDetail.setUserid(row.getLong(0));  
                sessionDetail.setSessionid(row.getString(1));  
                sessionDetail.setPageid(row.getLong(2));  
                sessionDetail.setActionTime(row.getString(3));
                sessionDetail.setSearchKeyword(row.getString(4));  
                sessionDetail.setClickCategoryId(row.getLong(5));  
                sessionDetail.setClickProductId(row.getLong(6));   
                sessionDetail.setOrderCategoryIds(row.getString(7));  
                sessionDetail.setOrderProductIds(row.getString(8));  
                sessionDetail.setPayCategoryIds(row.getString(9)); 
                sessionDetail.setPayProductIds(row.getString(11));  

                ISessionDetailDAO sessionDetailDAO = DAOFactory.getSessionDetailDAO();
                sessionDetailDAO.insert(sessionDetail);  
            }
        });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值