Flink用来处理流式数据源源不断,这时为了更加方便的处理流式数据一种方法就是将流式数据切割成有限的数据块进行处理,这个数据块被称为窗口。
窗口不是一个封闭的框,更像一个桶,一个可以存放数据的数据桶,窗口可以把数据流切割成有限大小的多个数据桶,每个数据都会存放到相应的数据桶中,当到达窗口结束时再对桶中的数据进行计算处理。
1. 按照驱动类型分类:
①时间窗口:
以时间类定义窗口的开始和结束,到达结束时间时,窗口不再收集数据,触发计算输出结果,并将窗口关闭销毁。
Flink的时间窗口是用于处理时间序列数据的一种机制。在Flink中,可以通过设置TimeWindow来定义时间窗口的大小和滑动间隔。
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
object TimeWindowExample {
def main(args: Array[String]): Unit = {
// 创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从socket源读取数据
val text = env.socketTextStream("localhost", 9999)
// 将数据转换为事件
val events = text.flatMap { line =>
val fields = line.split(",")
if (fields.length == 2) Some((fields(0), fields(1).toLong)) else None
}
// 定义时间窗口大小为5秒,滑动间隔为3秒
val windowSize = Time.seconds(5)
val slideSize = Time.seconds(3)
// 对事件进行时间窗口操作
val result = events
.keyBy(0)
.timeWindow(windowSize, slideSize)
.reduce((a, b) => (a._1 + b._1, a._2))
// 打印结果
result.print()
// 启动Flink程序
env.execute("TimeWindow Example")
}
}
这个例子中,我们首先创建了一个执行环境,然后从socket源读取数据并将其转换为事件。接着,我们定义了时间窗口的大小为5秒,滑动间隔为3秒,并对事件进行时间窗口操作。最后,我们打印了结果并启动了Flink程序。
② 计数窗口:
以元素的个数截取数据,到达固定的个数时就触发计算并关闭窗口。
Flink的计数窗口是用于处理数据流中固定数量的元素的一种机制。在Flink中,可以通过设置CountWindow来定义计数窗口的大小。
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.CountWindow
object CountWindowExample {
def main(args: Array[String]): Unit = {
// 创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从socket源读取数据
val text = env.socketTextStream("localhost", 9999)
// 将数据转换为事件
val events = text.flatMap { line =>
val fields = line.split(",")
if (fields.length == 2) Some((fields(0), fields(1).toLong)) else None
}
// 定义计数窗口大小为5,滑动间隔为3秒
val windowSize = Time.seconds(5)
val slideSize = Time.seconds(3)
// 对事件进行计数窗口操作
val result = events
.keyBy(0)
.timeWindow(CountWindow.of(windowSize, slideSize))
.reduce((a, b) => (a._1 + b._1, a._2))
// 打印结果
result.print()
// 启动Flink程序
env.execute("CountWindow Example")
}
}
这个例子中,我们首先创建了一个执行环境,然后从socket源读取数据并将其转换为事件。接着,我们定义了计数窗口的大小为5,滑动间隔为3秒,并对事件进行计数窗口操作。最后,我们打印了结果并启动了Flink程序。
①滚动窗口:
滚动窗口有固定的大小,是一种对数据进行“均匀切片”的划分方式。窗口之间没有重叠,也不会有间隔,是“首尾相接”的状态。
Flink的滚动窗口是用于处理数据流中固定时间间隔内的数据的一种机制。在Flink中,可以通过设置TimeWindow和Trigger来定义滚动窗口的大小和触发方式。
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.streaming.api.windowing.triggers.Trigger
object RollingWindowExample {
def main(args: Array[String]): Unit = {
// 创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从socket源读取数据
val text = env.socketTextStream("localhost", 9999)
// 将数据转换为事件
val events = text.flatMap { line =>
val fields = line.split(",")
if (fields.length == 2) Some((fields(0), fields(1).toLong)) else None
}
// 定义滚动窗口大小为5秒,滑动间隔为3秒
val windowSize = Time.seconds(5)
val slideSize = Time.seconds(3)
// 对事件进行滚动窗口操作
val result = events
.keyBy(0)
.timeWindow(TimeWindow.of(windowSize, slideSize))
.reduce((a, b) => (a._1 + b._1, a._2))
// 打印结果
result.print()
// 启动Flink程序
env.execute("RollingWindow Example")
}
}
这个例子中,我们首先创建了一个执行环境,然后从socket源读取数据并将其转换为事件。接着,我们定义了滚动窗口的大小为5秒,滑动间隔为3秒,并对事件进行滚动窗口操作。最后,我们打印了结果并启动了Flink程序。
②滑动窗口:
滑动窗口的大小固定的。窗口之间可以“错开”一定的位置。定义滑动窗口的参数有两 个:除去窗口大小之外,还有一个“滑动步长”,它其实就代表了窗口计算的频率。
Flink的滑动窗口是用于处理数据流中固定时间间隔内的数据的一种机制。在Flink中,可以通过设置TimeWindow和Trigger来定义滑动窗口的大小和触发方式。
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.streaming.api.windowing.triggers.Trigger
object SlidingWindowExample {
def main(args: Array[String]): Unit = {
// 创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从socket源读取数据
val text = env.socketTextStream("localhost", 9999)
// 将数据转换为事件
val events = text.flatMap { line =>
val fields = line.split(",")
if (fields.length == 2) Some((fields(0), fields(1).toLong)) else None
}
// 定义滑动窗口大小为5秒,滑动间隔为3秒
val windowSize = Time.seconds(5)
val slideSize = Time.seconds(3)
// 对事件进行滑动窗口操作
val result = events
.keyBy(0)
.timeWindow(TimeWindow.of(windowSize, slideSize))
.reduce((a, b) => (a._1 + b._1, a._2))
// 打印结果
result.print()
// 启动Flink程序
env.execute("SlidingWindow Example")
}
}
这个例子中,我们首先创建了一个执行环境,然后从socket源读取数据并将其转换为事件。接着,我们定义了滑动窗口的大小为5秒,滑动间隔为3秒,并对事件进行滑动窗口操作。最后,我们打印了结果并启动了Flink程序。
③会话窗口:
数据来了之后就开启一个会话窗口,如果接下来还有数据陆续到来,那么就一直保持会话;如果一段时间一直没收到数据,那就认为会话超时失效,窗口自动关闭。
如果相邻两个数据到来的时间间隔a小于指定的大小b,那说明还在保持会话,它们就属于同一个窗口;如果a 大于 b,那么新来的数据就应该属于新的会话窗口,而前一个窗口就应该关闭了。
乱序流下,每来一个新的数据,都会创建一个新的会话窗口;然后判断已有窗口之间的距离,如果小于给定的 b,就对它们进行合并操作。
会话窗口只能基于时间来定义 。
Flink的会话窗口是用于处理数据流中连续一段时间内的数据的一种机制。在Flink中,可以通过设置SessionWindow来实现会话窗口。
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.SessionWindow
object SessionWindowExample {
def main(args: Array[String]): Unit = {
// 创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从socket源读取数据
val text = env.socketTextStream("localhost", 9999)
// 将数据转换为事件
val events = text.flatMap { line =>
val fields = line.split(",")
if (fields.length == 2) Some((fields(0), fields(1).toLong)) else None
}
// 对事件进行会话窗口操作
val result = events
.keyBy(0)
.window(SessionWindow.withGap(Time.seconds(5)))
.reduce((a, b) => (a._1 + b._1, a._2))
// 打印结果
result.print()
// 启动Flink程序
env.execute("SessionWindow Example")
}
}
这个例子中,我们首先创建了一个执行环境,然后从socket源读取数据并将其转换为事件。接着,我们对事件进行会话窗口操作,将所有元素放入一个会话窗口中,会话窗口的时间间隔为5秒。最后,我们打印了结果并启动了Flink程序。
④全局窗口:
全局窗口会把相同 key 的所有数据都分配到同一个窗口中;无界流的数据永无止尽,所以这种窗口也没有结束的时候,默认是不会做触发计算的。
如果希望它能对数据进行计算处理,还需要自定义“触发器”。
Flink的全局窗口是用于处理数据流中所有元素的一种机制。在Flink中,可以通过设置GlobalWindow来实现全局窗口。
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.GlobalWindow
object GlobalWindowExample {
def main(args: Array[String]): Unit = {
// 创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从socket源读取数据
val text = env.socketTextStream("localhost", 9999)
// 将数据转换为事件
val events = text.flatMap { line =>
val fields = line.split(",")
if (fields.length == 2) Some((fields(0), fields(1).toLong)) else None
}
// 对事件进行全局窗口操作
val result = events
.keyBy(0)
.window(GlobalWindow.create())
.reduce((a, b) => (a._1 + b._1, a._2))
// 打印结果
result.print()
// 启动Flink程序
env.execute("GlobalWindow Example")
}
}
这个例子中,我们首先创建了一个执行环境,然后从socket源读取数据并将其转换为事件。接着,我们对事件进行全局窗口操作,将所有元素放入一个全局窗口中。最后,我们打印了结果并启动了Flink程序。