Flink —— 滑动窗口 延迟等待

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

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值