Spark Streaming 开窗函数 reduceByKeyAndWindow

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zimiao552147572/article/details/88558177

Spark Streaming 开窗函数 reduceByKeyAndWindow 统计一定时间内的热门词汇:DStream操作实战(reduceByKeyAndWindow开窗函数实现热门词汇统计)
        1.架构图


        2.实现流程
            1.安装并启动生产者:yum -y install nc
                首先在linux服务器上用YUM安装nc工具,nc命令是netcat命令的简称,它是用来设置路由器。我们可以利用它向某个端口发送数据。
            2.通过netcat工具向指定的端口发送数据(作为数据的生产者):nc -lk 9999 # 输入 nc -lk 端口号 之后就能在交互模式下输入数据进行发送

          3.编写Spark Streaming程序:
            当前程序为以5秒划分数据为一个批次,然后每隔10s计算一次当前窗口大小为10s内的数据,即一次计算2个批次的函数据,
            最后还将单词出现次数最多的前3位进行输出打印。
            package cn.test.spark
            import org.apache.spark.rdd.RDD
            import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
            import org.apache.spark.streaming.{Seconds, StreamingContext}
            import org.apache.spark.{SparkConf, SparkContext}

            //Spark Streaming 开窗函数 reduceByKeyAndWindow 统计一定时间内的热门词汇
            object SparkStreamingTCPWindowHotWords 
            {
                def main(args: Array[String]): Unit = 
                {
                        //配置sparkConf参数
                    //setMaster("local[2]"):本地模式运行,启动两个线程
                    //设置master的地址local[N] ,n必须大于1,其中1个线程负责去接受数据,另一线程负责处理接受到的数据
                            val sparkConf: SparkConf = new SparkConf().setAppName("SparkStreamingTCPWindowHotWords").setMaster("local[2]")
                            //构建sparkContext对象
                            val sc: SparkContext = new SparkContext(sparkConf)
                        //设置日志输出的级别
                            sc.setLogLevel("WARN")
                        //构建StreamingContext对象,每个批处理的时间间隔,即以多少秒内的数据划分为一个批次 ,当前设置 以5秒内的数据 划分为一个批次,
                     //每一个batch(批次)就构成一个RDD数据集。DStream就是一个个batch(批次)的有序序列,时间是连续的,
                    //按照时间间隔将数据流分割成一个个离散的RDD数据集。 
                            val scc: StreamingContext = new StreamingContext(sc, Seconds(5))
                            //使用“nc -lk 9999”生产数据并发送到9999端口,因此需要设置监听“IP:9999端口”,用来收集数据 
                            val lines: ReceiverInputDStream[String] = scc.socketTextStream("192.168.25.100",9999)
                    //flatMap(_.split(" ")) 流的扁平化,最终输出的数据类型为一维数组Array[String],所有单词都被分割出来作为一个元素存储到同一个一维数组Array[String]
                            val words: DStream[String] = lines.flatMap(_.split(" "))
                            //每个单词记为1
                    //map((_,1))每个单词记为1,即(单词,1),表示每个单词封装为一个元祖,其key为单词,value为1,返回MapPartitionRDD数据
                            val wordAndOne: DStream[(String, Int)] = words.map((_,1))
                            /* reduceByKeyAndWindow函数的三个参数的意义:
                        1.第一个参数reduceFunc:需要一个函数
                                 2.第二个参数windowDuration:
                            窗口长度:窗口框住的是一段时间内的数据,即窗口负责框住多少个批次的数据。
                            比如:设置窗口长度为10秒,然后如果以5秒内的数据划分为一个批次的话,
                                  那么这个10秒长度的窗口便框住了2个批次的数据。
                                 3.第三个参数slideDuration:
                            窗口滑动的时间长度:每隔“滑动指定的”时间长度计算一次,并且每当计算完毕后,窗口就往前滑动指定的时间长度。
                            比如:窗口滑动的时间长度为10秒的话,那么窗口每隔10秒计算一次,并且每当计算完毕后,窗口就往前滑动10秒。
                            比如:设置窗口长度为10秒,并且以5秒内的数据划分为一个批次的话,
                                  那么这个10秒长度的窗口便框住了2个批次的数据,而如果又设置了窗口滑动的时间长度为10秒的话,
                                  意味着窗口每隔10秒就计算一次,并且每当计算完毕后,窗口就往前滑动10秒。
                        4.结论:窗口长度和窗口滑动的时间长度必须为批次时间间隔的整数倍。
                                窗口长度和窗口滑动的时间长度必须一致相同。
                                窗口长度大于窗口滑动的时间长度,那么窗口仍然框住了部分已经计算过的批次数据,最终部分批次数据便会被重复计算
                                窗口长度小于窗口滑动的时间长度,那么窗口并无法框住部分还没计算过的批次数据,最终部分批次数据便丢失
                    */
                    //当前程序为以5秒划分数据为一个批次,然后每隔10s计算一次当前窗口大小为10s内的数据,即一次计算2个批次的函数据
                            val result: DStream[(String, Int)] = wordAndOne.reduceByKeyAndWindow((a:Int,b:Int)=>a+b, Seconds(10), Seconds(10))

                    //将单词出现次数最多的前3位进行输出打印
                            val data=result.transform(rdd =>
                        {
                              //降序处理后,取前3位。false表示降序
                        //数组/元祖._下标值”,下标值从1开始。那么t._2 表示为取出单词出现次数Int来进行后面的sortBy降序排序操作
                              val dataRDD: RDD[(String, Int)] = rdd.sortBy(t=>t._2, false)  
                              val sortResult: Array[(String, Int)] = dataRDD.take(3) //取前3位
                              println("--------------print top 3 begin--------------")
                              sortResult.foreach(println)
                              println("--------------print top 3 end--------------")
                              dataRDD
                            })
                            data.print()
                            scc.start()
                            scc.awaitTermination()
                      }
            }

        4.执行查看效果
            1.先执行:nc -lk 9999 

            2.然后再执行以上程序代码

            3.不断地在“nc -lk 9999”中输入不同的单词,观察IDEA控制台输出


            4.现象:当前程序为以5秒划分数据为一个批次,然后每隔10s计算一次当前窗口大小为10s内的数据,即一次计算2个批次的函数据,
                最后还将单词出现次数最多的前3位进行输出打印。

猜你喜欢

转载自blog.csdn.net/zimiao552147572/article/details/88558177
今日推荐