Session Windows
会话窗口原理
- 会话窗口根据会话的活跃元素情况进行分组,类似于web应用的Session,超过Session生命周期不访问,Session就关闭,下次发访问生成新的会话,对应Flink就是一段时间(session gap间隙)没有接收到新数据,即当一个不活动间隙发生时就会关闭上一个窗口,后续数据会分配到新的窗口,session gap间隙分为两种,一种时
static session gap
静态间隙,即间隙不变,一种是dynamic session gap
动态间隙,即间隙不固定。
会话窗口的特点
- 与滚动窗口和滑动窗口不同,会话窗口没有重叠
- 时间无对齐,也没有固定的开始和结束时间
- 只基于时间,不基于计数
- 会话窗口分配器可以配置一个静态会话间隙,也可以配置一个会话间隙提取器函数,该函数定义了不固定会话间隙(
动态会话间隙
)
会话窗口场景
- 计算某个会话周期内的(session gap间隙)聚合数据
会话窗口示例图如下:
代码
如果不懂,需要看一下前面的“Time和Window”的文章 运行代码查看结果进行对比
package 复习
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.api.scala._
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.assigners.{EventTimeSessionWindows, ProcessingTimeSessionWindows, SessionWindowTimeGapExtractor}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
/**
*session Windows 会话窗口
*处理时间滚动窗口输入数据:
2022-5-18 beijing 1648806746000 3
2022-5-18 beijing 1648806749000 3
2022-5-18 beijing 1648806751000 3
2022-5-18 beijing 1648806752000 2
2022-5-18 beijing 1648806757000 2
*/
object Session_Window {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1) // 注意:在事件时间中一定设置并行度,否则需要大量数据才能看到效果
val ds = env.socketTextStream("localhost", 6666)
.map(x => {
val fields: Array[String] = x.split(" ")
val date = fields(0).trim
val province = fields(1)
val ts = fields(2).trim.toLong
val dynamicGap = fields(3).trim.toInt
(date + "_" + province, ts,dynamicGap)
})
// 设置超时,为了事件时间提取时间戳还可以设置延迟
.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[(String, Long, Int)](Time.seconds(0)) {
override def extractTimestamp(t: (String, Long, Int)): Long = t._2
})
.keyBy(x=>x._1)
// 静态间隙基于事件时间的会话窗口
// .window(EventTimeSessionWindows.withGap(Time.seconds(5)))
// 动态间隙基于事件时间的会话窗口
// .window(EventTimeSessionWindows.withDynamicGap(new SessionWindowTimeGapExtractor[(String,Long,Int)] {
// override def extract(t: (String, Long, Int)): Long = t._3*1000l
// }))
// 静态间隙基于处理时间的会话窗口
// .window(ProcessingTimeSessionWindows.withGap(Time.seconds(5)))
// 动态间隙基于处理时间的会话窗口 这里的范型是输入的类型
.window(ProcessingTimeSessionWindows.withDynamicGap(new SessionWindowTimeGapExtractor[(String,Long,Int)] {
override def extract(t: (String, Long, Int)): Long =t._3*1000l
}))
.process(new ProcessWindowFunction[(String,Long,Int),String,String,TimeWindow] {
override def process(key: String, context: Context, elements: Iterable[(String, Long, Int)], out: Collector[String]): Unit = {
val start = context.window.getStart
val end = context.window.getEnd
out.collect(s"""累计开始时间:${start},累计结束时间: ${end}, 数据条数:${elements.size},数据内容:${elements}""".stripMargin)
}
}).print()
env.execute("test 06")
}
}