Spark中的Window滑动窗口之热点搜索词滑动统计!

package com.bynear.spark_Streaming;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaPairDStream;
import org.apache.spark.streaming.api.java.JavaReceiverInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import scala.Tuple2;

import java.util.List;

/**
 * 2018/5/15
 * 14:28
 * 热点搜索词滑动统计,每隔10s,统计最近60s的搜搜词的搜索频次,并打印出排名最靠前的3个搜索词以及出现的次数。
 */
public class WindowOprition {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("window").setAppName("local[2]");
        JavaSparkContext jsc = new JavaSparkContext(conf);
        JavaStreamingContext jssc = new JavaStreamingContext(jsc, Durations.seconds(5));
        /**搜索日志的格式
         * leo hello
         * tom world
         */
        JavaReceiverInputDStream<String> searchLogsDStream = jssc.socketTextStream("localhost", 9999);
        /**将搜索日志进行转换,只搜索一个词即可
         */
        JavaDStream<String> searchWordsDStream = searchLogsDStream.map(new Function<String, String>() {
            @Override
            public String call(String searchLog) throws Exception {
//                return searchLog.split(" ")[1];
                return searchLog;
            }
        });
//        将搜索词映射为(word,1)的Tuple格式
        JavaPairDStream<String, Integer> searchWordPairDStream = searchWordsDStream.mapToPair(new PairFunction<String, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(String searchWord) throws Exception {
                return new Tuple2<String, Integer>(searchWord, 1);
            }
        });
        /**
         *针对(word,1)的Tuple格式的DStream,执行reduceByKeyAndWindow,滑动窗口操作
         *第二个参数为,窗口长度,60s
         *第三个参数为,滑动间隔,10s
         * 也就是说,每个10s,将最近的60s的数据,作为一个窗口,进行内部的RDD聚合,然后统一对一个RDD进行后续的计算
         * 所有,这里的意思是,之前的searchWordPairDStream为止,其实都不会立即进行计算的
         * 而只是放在那里,然后,等到我们的滑动间隔到了以后,10s到了,会将之前的60s的RDD,||||||因为一个batch的间隔是5s,所以之间的60s
         * 就有12个RDD|||||||,给聚合起来,然后 统一执行reduceByKey操作,
         * 所以这里的reducebyKeyAndWindow,是针对每个窗口执行计算的,而不是针对某个DStream中的RDD
         */
        JavaPairDStream<String, Integer> searchWordCountsDStream = searchWordPairDStream.reduceByKeyAndWindow(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer num1, Integer num2) throws Exception {
                return num1 + num2;
            }
        }, /*窗口长度*/Durations.seconds(60),/*滑动间隔*/ Durations.seconds(10));
        //到这里为止,就可以做到,每隔10s,出来之前60s的收集的单词的统计次数
        //只想transform操作,因为,一个窗口,就是一个60s的数据,会变成一个RDD,然后,针对这一个RDD
        //根据每个搜索词出现的次数  进行排序,然后获取排名前三名的热点词
        JavaPairDStream<String, Integer> finalDStream = searchWordCountsDStream.transformToPair(new Function<JavaPairRDD<String, Integer>, JavaPairRDD<String, Integer>>() {
            @Override
            public JavaPairRDD<String, Integer> call(JavaPairRDD<String, Integer> searchWordCountsRDD) throws Exception {
                JavaPairRDD<Integer, String> countSearchWordsRDD = searchWordCountsRDD.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
                    //                映射为(number,word)
                    @Override
                    public Tuple2<Integer, String> call(Tuple2<String, Integer> tuple) throws Exception {
                        return new Tuple2<Integer, String>(tuple._2, tuple._1);
                    }
                });
//                根据number 作为key 进行排序
                JavaPairRDD<Integer, String> sortedCountSearchWordsRDD = countSearchWordsRDD.sortByKey(false);
//                映射为(word,number)
                JavaPairRDD<String, Integer> sortedSearchWordCountsRDD = sortedCountSearchWordsRDD.mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
                    @Override
                    public Tuple2<String, Integer> call(Tuple2<Integer, String> tuple) throws Exception {
                        return new Tuple2<String, Integer>(tuple._2, tuple._1);
                    }
                });
//                通过take(n) 获取排序后 前n个热点词
                List<Tuple2<String, Integer>> hogSearchWordCounts = sortedSearchWordCountsRDD.take(3);
                for (Tuple2<String, Integer> wordCount : hogSearchWordCounts) {
                    System.out.println(wordCount._1 + ":" + wordCount._2);
                }
                return searchWordCountsRDD;
            }
        });
        finalDStream.print();


        jssc.start();
        jssc.awaitTermination();
        jssc.stop();
        jsc.close();
    }
}

执行结果:::::(代码中有部分调整,输入的日志格式有 (name word) 修改成了只输入一个关键词word,便于测试! )
nc -lk 9999 窗口 不断输入内容
运行窗口,每隔10s统计一下 之前60s内热点词出现的热点词的前三名:
统计出来的结果不断在变化! 因为

0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160

0~10 输入 1 2 2 3 3 3 4 4 4 5 5 5 5 5 6 6 6
显示为(1,1)(2,2)(3,3)(4,3)(5,5)(6,3){未排序}
10~20 输入 1 2 3
显示 (1,2)(2,3)(3,4)(4,3)(5,5)(6,3){未排序}
20~30输入 1 2 3
显示 (1,3)(2,4)(3,5)(4,3)(5,5)(6,3){未排序}
30~40 输入 1 2 3
显示 (1,4)(2,5)(3,6)(4,3)(5,5)(6,3){未排序}
40~50 输入 1 2 3
显示 (1,5)(2,6)(3,7)(4,3)(5,5)(6,3){未排序}
50~60 输入 1 2 3
显示 (1,6)(2,7)(3,8)(4,3)(5,5)(6,3){未排序}
60~70 输入 hello word
此时0~10已经不再60s内,所有0~10内输入的单词 被清除掉了
00~10的输入1 2 2 3 3 3 4 4 4 5 5 5 5 5 6 6 6
50~60的显示(1,6)(2,7)(3,8)(4,3)(5,5)(6,3){未排序}
最后的显示为 (1,5)(2,5)(3,5)(hello,1)(word,1)
70~80 输入 zjs lt
此时 10~20的数据不存在了
10~20的输入 1 2 3
60~70的显示 (1,5)(2,5)(3,5)(hello,1)(word,1)
最终的显示为 (1,4)(2,4)(3,4)(hello,1)(word,1)(zjs,1)(lt,1)

以此类推………………

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值