spark学习笔记之spark core 取topN

spark学习笔记之spark core 取topN

初入职场的菜鸟,业务上遇到一个取topN的问题,要求是分组取app top5,这些app数据存储在Hive表里分属在5个不同字段,也就是说一条用户数据里有5个app,例如:

北京|qq|微信|手机百度|微博|淘宝
北京|微信|京东|头条|微博|appstore
上海|qq|支付宝|手机百度|微博|淘宝
上海|优酷|饿了么|||
...
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

根据业务需求,本来利用sparl-sql的开窗函数就可以一条sql语句轻松解决,但是公司的Spark集群版本太低,不支持开窗,无奈之下写程序来解决,为防止后续再遇此类问题,因此做笔记以记录

闲篇扯完我们来进入正题:

思路:

步骤一:统计每个市下的每个app的总数,统计成如下形式:

北京|qq,888
北京|微信,999
广州|支付宝,777
北京|京东,567
上海|淘宝,666
上海|qq,999
北京|微博,789
深圳|头条,555
...
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
从文件获取RDD<String>:
SparkConf conf = new SparkConf()
    .setAppName("sparktest")
    .setMaster("local");
@SuppressWarnings("resource")
JavaSparkContext sc = new JavaSparkContext(conf);

JavaRDD<String> lines = sc.textFile("d:/test.txt")


 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
JavaPairRDD<String, Integer> multipleRDD = lines.flatMapToPair(new PairFlatMapFunction<String, String, Integer>() {
    private static final long serialVersionUID = 1L;

    /**
    * PairFlatMapFunction类 包含一个返回Iterable迭代器的抽象方法,精华在于此,迭代器可迭代包含多个Tuple2的List集合
    */
    @Override
    public Iterable<Tuple2<String, Integer>> call(String line) throws Exception {
        // TODO Auto-generated method stub
        final String[] lineSplited = line.split("\\|"); 
        Iterable<Tuple2<String, Integer>> iterable = new Iterable<Tuple2<String,Integer>>() {

            @Override
            public Iterator<Tuple2<String, Integer>> iterator() {
                // TODO Auto-generated method stub
                // 将多个Tuple2放到List里
                List<Tuple2<String, Integer>> tuple2s = new ArrayList<Tuple2<String, Integer>>();
                //lineSplited[0]市
                String preKey = lineSplited[0];
                /**
                 * 遍历切分好的字段,判断该字段是那个信息,
                 * 如:下表1到5为app;把信息和preKey组成需要的key,相当于wordCount中的word
                 */
                for (int i = 0; i < lineSplited.length; i++) {

                    if(i >=1 && i <= 5){
                        /**
                         * 单个用户的appTop5
                         */
                        tuple2s.add(new Tuple2<String, Integer>(preKey+"|"+lineSplited[i],Integer.valueOf(1)));
                    }
                }
                //返回迭代;
                return tuple2s.iterator();
            }
        };
        return iterable;
    }
}).reduceByKey(new  Function2<Integer, Integer, Integer>() {
        private static final long serialVersionUID = 1L;

        @Override
        public Integer call(Integer i1, Integer i2) {
            return i1 + i2;
        }
});



 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

步骤二:对步骤一得出的汇总结果以市作为key分组:

----------
北京,qq|888
北京,微信|999
北京,京东|567
北京,微博|789
...
----------
上海,淘宝|666
上海,qq|999
...
----------
...
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
JavaPairRDD<String,String> grouped = multipleRDD.mapToPair(new PairFunction<Tuple2<String, Integer>, String, String>() {
    private static final long serialVersionUID = 1L;

    @Override
    public Tuple2<String, String> call(Tuple2<String, Integer> arg0) throws Exception {
        // TODO Auto-generated method stub
        String[] string = arg0._1.split("\\|");
        String str1 = string[0]; //key
        return new Tuple2<String, String>(str1,string[1]+"|"+arg0._2);

    }
}).groupByKey();



 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

步骤三:对步骤二得出的结果分市从大到小排序并取top5组成以”|”分隔的字符串:

----------
北京,微信|999
北京,qq|888
北京,微博|789
北京,京东|567
...
----------
上海,qq|999
上海,淘宝|666
...
----------
...
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

北京|微信|qq|微博|京东|淘宝
上海|微博|qq|微信|京东|手机百度
...
 
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
JavaPairRDD<String, String> groupedTopN = grouped.mapToPair(new PairFunction<Tuple2<String,Iterable<String>>, String, String>() {
    private static final long serialVersionUID = 1L;

    /**
    * 这里的关键是组合字段和排序
    * list.sort(new Comparator),用比较器排序
    */
    @Override
    public Tuple2<String, String> call(Tuple2<String, Iterable<String>> arg0) throws Exception {
        // TODO Auto-generated method stub
        Iterator<String> iterable = arg0._2.iterator();
        /**
         * 最终字符串信息初始化,
         */
        String str = arg0._1;
        //存一个分组下的存所有app
        List<String> list1 = new ArrayList<String>();
        List<String> appTop5;
        /**
         * 迭代一个key,得到其下的所有value
         */
        while (iterable.hasNext()) {
            //切分value并转换为list
            String[] strings =iterable.next().split("\\|");
            list1 = Arrays.asList(strings);

        }
        /**
         * app排序
         */
        Collections.sort(list1, new Comparator<String>() {
            //把app|count切分,按count数量排序
            @Override
            public int compare(String o1, String o2) {
                // TODO Auto-generated method stub
                int i1 = Integer.parseInt(o1.split("\\|")[1]);
                int i2 = Integer.parseInt(o2.split("\\|")[1]);
                return -(i1 - i2);//逆序
            }
        });
        /**
         * 取appTop5
         */
        if(list1.size()<5){
            appTop5 = list1;
        }else{
            appTop5 = list1.subList(0, 5);
        }

        //组字符串
        for (String string : apps) {
            str +="|"+string;
        }

        return new Tuple2<String, String>(arg0._1,str);
    }

});



 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

步骤四:持久化到HDFS入Hive表或到控制台

/**
 * 输出到控制台
 */
groupedTopN.foreach(new VoidFunction<Tuple2<String,String>>() {

    @Override
    public void call(Tuple2<String, String> arg0) throws Exception {
        // TODO Auto-generated method stub
        System.out.println(arg0._2);
    }
});


 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
/**
 * 输出到文件
 */
finalRDD.rdd().saveAsTextFile(outputPath);


 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

需要的jar包:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值