一、Window窗口
Flink批处理是流处理的一个特例,所以Flink底层引擎是一个流式引擎,在上面实现了流处理和批处理,而window是流处理到批处理的一个桥梁
-
Window是一种可以把无界数据切割为有界数据块的手段
因为对流的所有元素进行计数是不可能的,因为通常流是无限的,或者称为是无界的。所以流上的聚合需要由window来划分范围
-
Window可以是时间驱动的【Time Window】(eg:每30秒)或者数据驱动的【Count Window】(eg:每100个元素)
DataStream API提供了基于Time和Count的Window。DataStream API也提供了定制化的Window操作
1.1、TimeWindow
- tumbling window 滚动窗口(没有重叠)表示窗口数据没有重叠
- sliding window 滑动窗口(有重叠)
timeWindow(Time.seconds(10)) 表示滚动窗口的窗口大小为10秒,对每10秒内的数据进行聚合计算
timeWindow(Time.seconds(10),Time.seconds(5)) 表示滑动窗口的窗口大小为10秒,滑动间隔为5秒,就是每隔5秒计算前10秒内的数据
package com.strivelearn.flink.window;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;
/**
* @author strivelearn
* @version TimeWindowOp.java, 2023年01月17日
*/
public class TimeWindowOp {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> dataSourceWithSocket = executionEnvironment.socketTextStream("192.168.234.100", 9001);
// 需要设置时间语义
executionEnvironment.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
// TimeWindow 之 滚动窗口 ,每隔10s计算一次前10s时间窗口内的数据
// dataSourceWithSocket.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
// @Override
// public void flatMap(String s, Collector<Tuple2<String, Integer>> collector) throws Exception {
// String[] words = s.split(" ");
// for (String word : words) {
// collector.collect(new Tuple2<String, Integer>(word, 1));
// }
// }
// }).keyBy(0).timeWindow(Time.seconds(10)).sum(1).print();
// TimeWindow 之 滑动窗口 ,每隔5s计算一次前10s时间窗口内的数据
dataSourceWithSocket.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
@Override
public void flatMap(String s, Collector<Tuple2<String, Integer>> collector) throws Exception {
String[] words = s.split(" ");
for (String word : words) {
collector.collect(new Tuple2<String, Integer>(word, 1));
}
}
}).keyBy(0).
// 第一个参数:窗口大小,第二个参数:滑动间隔
timeWindow(Time.seconds(10), Time.seconds(5)).sum(1).print();
executionEnvironment.execute("TimeWindowOp");
}
}
1.2、CountWindow
根据元素个数对数据流切分窗口,CountWindow也可以支持滚动窗口和滑动窗口
countWindow(5) 表示滚动窗口的大小是5个元素,也就是当窗口中填满5个元素的时候,就会对窗口进行计算了
countWindow(5,1) 表示滑动窗口的窗口大小是5个元素,滑动的间隔为1个元素,也就是说每新增1个元素就会对前面5个元素计算一次
package com.strivelearn.flink.window;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;
/**
* @author strivelearn
* @version CountWindowOp.java, 2023年01月17日
*/
public class CountWindowOp {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> dataSourceWithSocket = executionEnvironment.socketTextStream("192.168.234.100", 9001);
// 需要设置时间语义
executionEnvironment.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
// CountWindow 之 滚动窗口 ,每隔5个元素计算一次前5个元素
// dataSourceWithSocket.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
// @Override
// public void flatMap(String s, Collector<Tuple2<String, Integer>> collector) throws Exception {
// String[] words = s.split(" ");
// for (String word : words) {
// collector.collect(new Tuple2<String, Integer>(word, 1));
// }
// }
// }).keyBy(0).countWindow(5).sum(1).print();
// TimeWindow 之 滑动窗口 ,每隔5s计算一次前10s时间窗口内的数据
dataSourceWithSocket.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
@Override
public void flatMap(String s, Collector<Tuple2<String, Integer>> collector) throws Exception {
String[] words = s.split(" ");
for (String word : words) {
collector.collect(new Tuple2<String, Integer>(word, 1));
}
}
}).keyBy(0).
// 第一个参数:窗口大小,第二个参数:滑动间隔
countWindow(5,1).sum(1).print();
executionEnvironment.execute("TimeWindowOp");
}
}
1.3、自定义window
其实window还可以再细分一下,一种是基于key的window,一种是不基于key的window
package com.strivelearn.flink.window;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;
/**
* 自定义TimeWindow
* @author strivelearn
* @version MyTimeWindow.java, 2023年01月20日
*/
public class MyTimeWindow {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> dataSourceWithSocket = executionEnvironment.socketTextStream("192.168.234.100", 9001);
// 需要设置时间语义
executionEnvironment.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
dataSourceWithSocket.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
@Override
public void flatMap(String s, Collector<Tuple2<String, Integer>> collector) throws Exception {
String[] words = s.split(" ");
for (String word : words) {
collector.collect(new Tuple2<>(word, 1));
}
}
}).keyBy(0)
// 自定义窗口大小
.window(TumblingEventTimeWindows.of(Time.seconds(10))).sum(1).print();
executionEnvironment.execute("MyTimeWindow");
}
}
1.4、Window聚合
-
增量聚合
窗口中每进入一条数据,就进行一次计算。
常用函数:reduce、aggregate、sum、min、max
-
全量聚合
等属于窗口的数据到齐,才开始进行聚合计算。(可以实现对窗口内的数据进行排序等需求)
常用的全量函数:apply(windowFunction)、process(processWindowFunction)。processWindowFunction比windowFunction提供了更多的上下文信息
二、Time
- Event Time:事件产生的时间,通常由事件中的时间戳描述
- Ingestion Time:事件进入Flink的时间
- Processing Time:事件被处理时当前系统的时间
eg:原始日志:2023-01-01 10:00:00 产生。日志进入Flink的时间是 2023-01-01 20:00:01。日志数据到达Window处理的时间是:2023-01-01 20:00:02
如果我们想要统计每分钟内接口调用失败的错误日志个数,使用哪个时间才有意义?如果使用数据进入Flink的时间或者Window处理的时间,其实是没有意义的。这个时候,我们需要使用原始日志的时间才是有意义的。
在Flink的流处理中默认使用的是哪个时间呢?
默认情况下,Flink在流处理中使用的时间是Processing Time。如果想要修改的话,怎么修改呢?
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) or
env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime)