Spark 2.x管理与开发-Spark Streaming-Spark Streaming进阶(四)【窗口操作】

Spark Streaming还提供了窗口计算功能,允许您在数据的滑动窗口上应用转换操作。

下图说明了滑动窗口的工作方式:

 

如图所示,每当窗口滑过originalDStream时,落在窗口内的源RDD被组合并被执行操作以产生windowed DStream的RDD。

在上面的例子中,操作应用于最近3个时间单位的数据,并以2个时间单位滑动。这表明任何窗口操作都需要指定两个参数。

1.窗口长度(windowlength- 窗口的时间长度(上图的示例中为:3

2.滑动间隔(slidinginterval- 两次相邻的窗口操作的间隔(即每次滑动的时间长度)(上图示例中为:2)。

这两个参数必须是源DStream的批间隔的倍数(上图示例中为:1)。

我们以一个例子来说明窗口操作。

假设您希望对之前的单词计数的示例进行扩展,每10秒钟对过去30秒的数据进行wordcount。

为此,我们必须在最近30秒的pairs DStream数据中对(word, 1)键值对应用reduceByKey操作。

这是通过使用reduceByKeyAndWindow操作完成的。

 

一些常见的窗口操作如下表所示。所有这些操作都用到了上述两个参数 - windowLength和slideInterval

1)window(windowLength, slideInterval)

基于源DStream产生的窗口化的批数据计算一个新的DStream

2)countByWindow(windowLength, slideInterval)

返回流中元素的一个滑动窗口数

3)reduceByWindow(func, windowLength, slideInterval)

返回一个单元素流。利用函数func聚集滑动时间间隔的流的元素创建这个单元素流。函数必须是相关联的以使计算能够正确的并行计算。

4)reduceByKeyAndWindow(func, windowLength, slideInterval, [numTasks])

应用到一个(K,V)对组成的DStream上,返回一个由(K,V)对组成的新的DStream。每一个key的值均由给定的reduce函数聚集起来。

注意:在默认情况下,这个算子利用了Spark默认的并发任务数去分组。你可以用numTasks参数设置不同的任务数

 5)reduceByKeyAndWindow(func, invFunc, windowLength, slideInterval, [numTasks])

上述reduceByKeyAndWindow() 的更高效的版本,其中使用前一窗口的reduce计算结果递增地计算每个窗口的reduce值。

这是通过对进入滑动窗口的新数据进行reduce操作,以及“逆减(inverse reducing)”离开窗口的旧数据来完成的。

一个例子是当窗口滑动时对键对应的值进行“一加一减”操作。但是,它仅适用于“可逆减函数(invertible reduce functions)”,即具有相应“反减”功能的减函数(作为参数invFunc)。

像reduceByKeyAndWindow一样,通过可选参数可以配置reduce任务的数量。 请注意,使用此操作必须启用检查点。

 6)countByValueAndWindow(windowLength, slideInterval, [numTasks])

应用到一个(K,V)对组成的DStream上,返回一个由(K,V)对组成的新的DStream。每个key的值都是它们在滑动窗口中出现的频率。

******自己操作******

Scala代码:

package streamingExamples
import org.apache.log4j.Logger
import org.apache.log4j.Level
import org.apache.spark.SparkConf
import org.apache.spark.SparkConf
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Seconds
import org.apache.spark.storage.StorageLevel

object MyNetworkWordCountByWindow {
  def main(args: Array[String]): Unit = {
    //下面的两行代码定义日志级别,可以减少打印出来的日志
    Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
    
    //一、创建运行时的环境
    //保证CPU的核数大于等于2,"local[2]"表示开启两个线程
    //一个线程用于读取数据,一个线程用于计算处理数据
    val conf =new SparkConf().setMaster("local[2]").setAppName("MyNetworkWordCountByWindow")
    //二、定时采样
    //因为SparkStreaming是将连续的数据流变成不连续的RDD,所以就是定时采样。
    //接收两个参数,其中:Seconds(3)是采样时间间隔,这里就是3秒
    val ssc=new StreamingContext(conf,Seconds(3))
    //三、创建DStream,从netcat服务器上读取数据
    //接收三个参数:地址,端口号,和RDD里缓存的位置一致(一般取默认值即可)
    //注意:IP可以不是Active状态主机的IP,只要是集群里的即可
    val lines=ssc.socketTextStream("192.168.212.111", 1234, StorageLevel.MEMORY_ONLY)
    //四、分词
    val words=lines.flatMap(_.split(" "))
    //五、计数
    val wordcount =words.map((_,1)) //每个单词后面都记一次数
    /**
     * 需求:每3秒把过去30秒的数据读取出来
     * 窗口的长度是30秒
     * 滑动距离是3秒
     * 也就是:每3秒钟进行移动一次,长度为30秒不变
     * 注意:每次移动的长度必须是采样时间间隔的整数倍,因为RDD不能被分割
     */
    val result=wordcount.reduceByKeyAndWindow((x:Int,y:Int)=>(x+y), Seconds(30), Seconds(3))
    //六、打印
    result.print()
    //注意:因为Spark Streaming程序是流式处理程序,所以可以不用关闭此程序
    //七、启动StreamingContext进行计算
    ssc.start()
    //八、等待任务结束
    ssc.awaitTermination()
  }
}

结果:

启动nc服务器:

[root@bigdata111 bin]# nc -l 1234

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3