eventTime+watermarker+allowedLateness

结论:窗口的关闭需要带 watermarker 的时间我想使用 kafkaUI 界面发送 json 数据给 kafka,json 数据长这个样子:

{"money":47,"orderId":"6ce94dcefaac4106bb7b66302bb9e785","timeStamp":176430

3530000,"uid":0}

这个数据我是编写了一个代码生成的

package com.bigdata.day04;

import com.alibaba.fastjson.JSON;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;


public class CreateOrderInfoJson {

    public static void main(String[] args) throws Exception {

        //1. env-准备环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        DataStreamSource<OrderInfo> streamSource = env.addSource(new MySource(), "自动创建订单");

        streamSource.map(new MapFunction<OrderInfo, String>() {

            @Override
            public String map(OrderInfo orderInfo) throws Exception {
                return JSON.toJSONString(orderInfo);
            }
        }).print();

        env.execute();
    }
}

编写一个 flink 读取 kafka 数据的代码

这个代码中可以读取 kafka 数据,并且必须使用 evenetTime 时间语义,并且还需要有watermarker+allowedLateness

package com.bigdata.day04;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SideOutputDataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.windowing.WindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;
import org.apache.flink.util.OutputTag;

import java.time.Duration;


public class TestAllowedLateness {

    public static void main(String[] args) throws Exception {

        //1. env-准备环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        KafkaSource<String> streamSource = KafkaSource.<String>builder().setBootstrapServers("bigdata01:9092").setTopics("first").setStartingOffsets(OffsetsInitializer.latest()).setValueOnlyDeserializer(new SimpleStringSchema()).build();

        DataStreamSource<String> dataStreamSource = env.fromSource(streamSource, WatermarkStrategy.noWatermarks(), "kafkaSource");
        //dataStreamSource.print();

        SingleOutputStreamOperator<OrderInfo> streamOperator = dataStreamSource.map(new MapFunction<String, OrderInfo>() {
            @Override
            public OrderInfo map(String json) throws Exception {
                return JSON.parseObject(json, OrderInfo.class);
            }
        });


        // 此处添加水印
        SingleOutputStreamOperator<String> result = streamOperator.assignTimestampsAndWatermarks(WatermarkStrategy.<OrderInfo>forBoundedOutOfOrderness(Duration.ofSeconds(3)).withTimestampAssigner(
                        new SerializableTimestampAssigner<OrderInfo>() {
                            // long 是时间戳吗?是秒值还是毫秒呢?年月日时分秒的的字段怎么办呢?
                            @Override
                            public long extractTimestamp(OrderInfo orderInfo, long recordTimestamp) {
                                // 这个方法的返回值是毫秒,所有的数据只要不是这个毫秒值,都需要转换为毫秒
                                return orderInfo.getTimeStamp();
                            }
                        }
                )).keyBy(order -> order.getUid()).window(TumblingEventTimeWindows.of(Time.seconds(5)))


                .allowedLateness(Time.seconds(10))

                .apply(new WindowFunction<OrderInfo, String, Integer, TimeWindow>() {
                    @Override
                    public void apply(Integer key, TimeWindow window, Iterable<OrderInfo> input, Collector<String> out) throws Exception {
                        // 返回   时间开始--> 时间结束  用户id   金额
                        long start = window.getStart();
                        long end = window.getEnd();
                        String startTime = DateFormatUtils.format(start, "yyyy-MM-dd HH:mm:ss");
                        String endTime = DateFormatUtils.format(end, "yyyy-MM-dd HH:mm:ss");
                        int sumMoney = 0;
                        for (OrderInfo orderInfo : input) {

                            sumMoney += orderInfo.getMoney();
                        }

                        out.collect(startTime + "->" + endTime + "->" + key + "-->" + sumMoney);

                    }
                });

        result.print();

        env.execute();
    }
}

开始测试:

使用 kafkaUI 界面发送第一条数据:

{"money":47,"orderId":"6ce94dcefaac4106bb7b66302bb9e785","timeStamp":1764303530000,"uid":0}

我使用时间戳转换器看一下是什么时候:

https://www.beijing-time.org/shijianchuo/

1764303530000 = 12:18:50 也就意味着 第一个区间是 [12:18:50,12:18:55)

控制台不会有输出,因为没有触发。

输入以下数据可以触发:12:18:58

{"money":47,"orderId":"6ce94dcefaac4106bb7b66302bb9e785","timeStamp":1764303538000,"uid":0}

得到了一个结论: 水印时间 (12:18:58)>= 区间结束时间 就会触发该区间的计算 【2025-11-28 12:18:50->2025-11-28 12:18:55)

此时这个 【2025-11-28 12:18:50->2025-11-28 12:18:55) 区间触发了,没有关闭

接着在这个区间【2025-11-28 12:18:50->2025-11-28 12:18:55)继续放入数据:

{"money":47,"orderId":"6ce94dcefaac4106bb7b66302bb9e785","timeStamp":1764303533000,"uid":0}
{"money":47,"orderId":"6ce94dcefaac4106bb7b66302bb9e785","timeStamp":1764303534000,"uid":0}

说明 添加了allowedLateness 之后,窗口的结束时间 不是

事件时间>= 窗口的结束时间+ allowedLateness

那关闭时间到底是多少?

事件时间 >= 窗口结束12:18:55 + watermarker(3s) + allowedLateness(10s)

### watermarker 图像处理与水印工具 watermarker是一个用于图像处理特别是添加水印的强大开源库。此库允许用户轻松地向图片添加文字或图形形式的水印,满足不同场景下的需求[^3]。 #### 功能特性 - **灵活性高**:支持自定义设置水印的位置、透明度和尺寸等参数。 - **兼容性强**:不仅能够处理静态图片文件,还支持GIF动态图的水印嵌入操作[^1]。 - **易于集成**:作为Python编写的软件包,可以方便地与其他应用和服务相结合,实现自动化批量化生产带有所需标记的照片素材[^2]。 #### 安装方法 为了开始使用watermarker,在本地环境中安装该库十分简单: ```bash pip install git+https://github.com/2Dou/watermarker.git ``` 这段命令会从GitHub仓库下载最新版本并完成安装过程。 #### 使用实例 下面给出一段基本的例子来展示如何利用watermarker给一张照片加上简单的文本型水印: ```python from PIL import Image, ImageDraw, ImageFont import os from watermarker.marker import add_mark input_image_path = 'path/to/input/image.jpg' output_image_path = 'path/to/output/image_with_watermark.png' text_watermark = "Your Watermark Text" font_size = 40 position = (10, 10) add_mark(input_image_path=input_image_path, output_image_path=output_image_path, text=text_watermark, font_size=font_size, position=position) ``` 上述代码片段展示了怎样调用`add_mark()`函数为指定路径中的输入图片添加带有特定字体大小及位置的文字水印,并保存到新的输出文件中去。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值