source:kafka
transform:求max
sink:控制台输出
package kb11.window;
import kb11.beans.SensorReading;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
import org.apache.flink.util.OutputTag;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import java.util.Properties;
/**
* @Author Xulihua
* @Date2021/6/30
* @Description
*/
public class Window3 {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 设定时间语义,以事件发生为 时间语义
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
Properties prop = new Properties();
prop.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.107.103:9092");
prop.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
prop.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
prop.put(ConsumerConfig.GROUP_ID_CONFIG, "group_kafkasource12");
// prop.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
// prop.setProperty(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
FlinkKafkaConsumer011<String> stringFlinkKafkaConsumer011 = new FlinkKafkaConsumer011<>("sensor", new SimpleStringSchema(), prop);
DataStreamSource<String> inputStream = env.addSource(stringFlinkKafkaConsumer011);
SingleOutputStreamOperator<SensorReading> mapStream = inputStream.map(new MapFunction<String, SensorReading>() {
@Override
public SensorReading map(String value) throws Exception {
String[] split = value.split(",");
return new SensorReading(split[0], Long.parseLong(split[1]), Double.parseDouble(split[2]));
}
}).
assignTimestampsAndWatermarks( // 处理乱序时间
new BoundedOutOfOrdernessTimestampExtractor<SensorReading>(Time.seconds(0)) {
@Override
public long extractTimestamp(SensorReading element) {
return element.getTimestamp() * 1000L;
}
});
// start - (start -offset + size)%size
SingleOutputStreamOperator<SensorReading> maxResultStream = mapStream.keyBy("id")
// .timeWindow(Time.seconds(12))
.window(TumblingEventTimeWindows.of(Time.seconds(15)))
.allowedLateness(Time.seconds(30))
// .sideOutputLateData(new OutputTag<SensorReading>("late"))
.max("temperature");
maxResultStream.print("max");
// DataStream<SensorReading> sideOutput = maxResultStream.getSideOutput(new OutputTag<SensorReading>("late"));
// sideOutput.print("late");
env.execute("flinkWindow");
}
}
说明:
滑动窗口时间:15秒
.timeWindow(Time.seconds(15))
延迟等待时间:30秒
.allowedLateness(Time.seconds(30))
窗口开启时间计算:
源码:
public WindowedStream<T, KEY, TimeWindow> timeWindow(Time size) {
if (environment.getStreamTimeCharacteristic() == TimeCharacteristic.ProcessingTime) {
return window(TumblingProcessingTimeWindows.of(size));
} else {
return window(TumblingEventTimeWindows.of(size));
}
}
我们启用的是 :以事件发生为时间语义
public static long getWindowStartWithOffset(long timestamp, long offset, long windowSize) {
return timestamp - (timestamp - offset + windowSize) % windowSize;
}
}
timestamp:window start时间
offset:时区矫正
windowSize:窗口大小
代码:
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
规定了是以事件开启时间为 window start时间
以 1624864152122 为事件开始时间 计算窗口开启时间:
1624864152122 - (1624864152122- 0 +15)%15=
1624864152120
也就是说第一个窗口开启时间为1624864152120
依次输入:
>sensor_3,1624864152122,36.3
>sensor_3,1624864152125,35.3
>sensor_3,1624864152130,37.8
>sensor_3,1624864152134,35.5
>sensor_3,1624864152135,38.6
字段为 id,timestamp,temp
输到35的时候满足第一个窗口的截止时间 控制台输出temp 最大的 37.8
为什么不是38.6, 因为15秒窗口是左闭右开
继续输入:
>sensor_3,1624864152138,34.6
>sensor_3,1624864152140,37.7
>sensor_3,1624864152126,38.2
出现38.2
原因:
当前被判定的最新时间到了 40 是在第一个窗口延迟时间(35-65)内 而26 就被认为是数据 遗漏的
且是第一个窗口的最大temp 所以出现
而第二个窗口的时间还没到输出时间(35-50)
截止时间为50
继续输入:
>sensor_3,1624864152142,38.6
>sensor_3,1624864152145,37.6
>sensor_3,1624864152149,39.9
>sensor_3,1624864152150,41.6
出现 39.9
原理和第一次输入的一样
继续输入:
>sensor_3,1624864152152,33.6
>sensor_3,1624864152156,35.7
>sensor_3,1624864152148,37.5
输出的是 :39.9
原因是,52 ,56 两条在第三个窗口大小范围内,没有到65截止时间,所以没输出,
当前被判定的最新时间为56 ,同时在第一个和第二个的延迟时间范围内,随之来的48 就被认为是第二个窗口的丢失数据,和原有的窗口二 的最大的39.9 进行比较 还是39.9 大 所以继续输出39.9
继续输入:
>sensor_3,1624864152158,36.4
>sensor_3,1624864152162,37.3
>sensor_3,1624864152170,38.8
出现了:41.6
原因:当前被判定的最新时间为70 是超过了第一个窗口的延迟时间(36-65)了,但是在第二个窗口的延迟时间(50-80)范围内,此时 就算是有满足第一个窗口的时间 也不会输出了 ,但是如果有满足第二个窗口的数据的话 会被放到第二个窗口进行比较,跟上面输出39.9的道理一样。而我们这边的时间是满足了第二个窗口的大小范围了 所以 对第三个窗口的数据进行比较得出 41.6(41.6对应的时间是50 左闭右开 是在第三个窗口里的)
继续输入:
sensor_3,1624864152149,38.7
出现39.9
原因:
同上,当前判定的时间为70 ,只满足第二个窗口的时间范围,和之前窗口二的最大值39.9进行比较 最大的还是39.9