sparkstreaming窗口函数reduceByKeyAndWindow

 

 首先是窗口操作普通机制

package com.fengrui.test

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext, streaming}

/**
  * SparkStreaming 窗口操作
  * reduceByKeyAndWindow只是一种特殊的实现,根据reduceByKey逻辑操作
  * 每隔窗口滑动间隔时间 计算窗口长度内的数据,按照指定方式处理
  * 比如说我每隔5秒钟想看过去15秒一共有多少个hello单词,这时候updateStateByKey就满足不了业务需求了
  */
object WindowOperator {

  def main(args: Array[String]): Unit = {

    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("WindowOperator")

    val sc = new SparkContext(conf)

    val ssc = new StreamingContext(sc,Durations.seconds(5))

    val lines: ReceiverInputDStream[String] = ssc.socketTextStream("hdp-1",9999)

    val words: DStream[String] = lines.flatMap(_.split(" "))

    val word: DStream[(String, Int)] = words.map((_,1))

    /**
      * 窗口操作普通机制
      * 第一个参数是监测的数据,第二个参数是窗口长度,第三个是滑动间隔
      * 代表每五秒查看前十五秒数据
      * 这里的时间必须是 batchinterval 整数倍
      */
    val res: DStream[(String, Int)] =
      word.reduceByKeyAndWindow((v1:Int,v2:Int) => {v1 + v2},Durations.seconds(15),Durations.seconds(5))

    res.print()

    ssc.start()
    ssc.awaitTermination()

  }

}

优化窗口操作

package com.fengrui.test

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext, streaming}

/**
  * SparkStreaming 窗口操作
  * reduceByKeyAndWindow只是一种特殊的实现,根据reduceByKey逻辑操作
  * 每隔窗口滑动间隔时间 计算窗口长度内的数据,按照指定方式处理
  * 比如说我每隔5秒钟想看过去15秒一共有多少个hello单词,这时候updateStateByKey就满足不了业务需求了
  */
object WindowOperator {

  def main(args: Array[String]): Unit = {

    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("WindowOperator")

    val sc = new SparkContext(conf)

    val ssc = new StreamingContext(sc,Durations.seconds(5))

    val lines: ReceiverInputDStream[String] = ssc.socketTextStream("hdp-1",9999)

    val words: DStream[String] = lines.flatMap(_.split(" "))

    val word: DStream[(String, Int)] = words.map((_,1))
   
    /**
      * 窗口操作优化的机制
      * 比如说我们还是每隔五秒查看一下前十五秒数据,我们可以加上新进来的批次,再减去出去的批次,防止任务堆积
      * 用优化机制必须设置checkpoint,不设置会报错
      * 第一个参数是先加上新来的批次
      * 第二个参数是减去出去的批次
      * 第三个参数是窗口长度
      * 第四个参数是滑动间隔
      */
      ssc.checkpoint("/test")

    val res: DStream[(String, Int)] = word.reduceByKeyAndWindow(
      (v1: Int, v2: Int) => {v1 + v2},
      (v1: Int, v2: Int) => {v1 - v2},
      Durations.seconds(15),
      Durations.seconds(15)
    )

    res.print()

    ssc.start()
    ssc.awaitTermination()

  }

}

也可以根据自己需求调用window

package com.fengrui.test

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext, streaming}

/**
  * SparkStreaming 窗口操作
  * reduceByKeyAndWindow只是一种特殊的实现,根据reduceByKey逻辑操作
  * 每隔窗口滑动间隔时间 计算窗口长度内的数据,按照指定方式处理
  * 比如说我每隔5秒钟想看过去15秒一共有多少个hello单词,这时候updateStateByKey就满足不了业务需求了
  */
object WindowOperator {

  def main(args: Array[String]): Unit = {

    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("WindowOperator")

    val sc = new SparkContext(conf)

    val ssc = new StreamingContext(sc,Durations.seconds(5))

    val lines: ReceiverInputDStream[String] = ssc.socketTextStream("hdp-1",9999)

    val words: DStream[String] = lines.flatMap(_.split(" "))

    val word: DStream[(String, Int)] = words.map((_,1))

    /**
      * 我们如果有自己的操作逻辑
      * 我们也可以使用Window
      */
    val win: DStream[(String, Int)] = word.window(Durations.seconds(15),Durations.seconds(5))

    val res: DStream[(String, Int)] = win.reduceByKey(_+_)

    res.print()

    ssc.start()
    ssc.awaitTermination()

  }

}

 

### Spark Streaming 支持窗口函数及其用法 #### 窗口函数的支持情况 Spark Streaming 完全支持窗口函数,这使得处理基于时间间隔的数据流变得简单有效。通过这些功能可以执行诸如聚合、过滤和其他复杂操作。 #### 参数解释 对于 `DStream` 而言,在应用窗口变换时涉及到两个重要参数:`windowDuration` 和 `slideDuration`。前者定义了窗口的总长度;后者则指定了每隔多久滑动一次窗口来创建新的批次[^1]。 #### 函数具体实现方式 以 `reduceByKeyAndWindow` 方法为例,此方法允许开发者指定用于更新状态值的操作——即当有新数据到来时应如何将其加入现有记录之中(`reduceFunc`) ,同时也提供了移除旧数据项的能力 (`invReduceFunc`) 。该过程涉及四个主要组成部分: - **reduceFunc**: 对新增加的数据片段进行规约运算。 - **invReduceFunc**: 当某些键对应的条目超出了当前活动窗口范围,则利用这个逆向减少函数去除那些不再属于最新窗口内的元素。 - **windowDuration**: 设定整个分析周期持续多长时间。 - **slideDuration**: 控制着每次向前推进多少秒形成下一个待处理区间[^2]。 下面给出一段简单的代码示例展示怎样运用上述概念构建一个每三秒钟汇总一次单词计数的应用程序,并且每一秒都会触发一轮计算: ```scala val words = socketDStream.flatMap(_.split(" ")) val pairs = words.map(word => (word, 1)) pairs.reduceByKeyAndWindow( (a: Int, b: Int) => a + b, Seconds(3), Seconds(1) ).print() ``` 这段脚本首先将输入字符串分割成单独词语并映射为二元组形式 `(word, count)`,接着调用了带有特定窗口配置的 `reduceByKeyAndWindow()` 来累积各词频次,最后打印结果至控制台[^3]。 值得注意的是,在实际应用场景下可能还需要考虑更多细节设置比如分区数目调整等优化措施以提高性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值