7、Flink 自定义 WaterMarkGenerator 案例

1、MyWaterMarkWatermarkGeneratorPeriodic

该 watermark 生成器场景:数据源在一定程度上乱序,即某个最新到达的时间戳为 t 的元素将在最早到达的时间戳为 t 的元素之后最多 n 毫秒到达。

bash 复制代码
class MyBoundedOutOfOrdernessGenerator implements WatermarkGenerator<_01_MyEvent> {
    // 3 秒
    private final long maxOutOfOrderness = 3000;

    private long currentMaxTimestamp;

    // 每到达一条数据执行一次,获取当前的最大时间戳
    @Override
    public void onEvent(_01_MyEvent event, long eventTimestamp, WatermarkOutput output) {
        currentMaxTimestamp = Math.max(currentMaxTimestamp, eventTimestamp);
        System.out.println("当前的数据ID为=>" + event.getId() + ",currentMaxTimestamp=>" + currentMaxTimestamp);
    }

    // 每到达一个周期触发一次,下发 Watermark
    @Override
    public void onPeriodicEmit(WatermarkOutput output) {
        // 发出的 watermark = 当前最大时间戳 - 最大乱序时间
        Watermark watermark = new Watermark(currentMaxTimestamp - maxOutOfOrderness - 1);
        output.emitWatermark(watermark);
        System.out.println("下发的 Watermark 为=>" + watermark.getTimestamp());
    }
}

数据输入与输出案例

bash 复制代码
  输入输出demo数据演示如下
 
  下发的 Watermark 为=>-3001
 
  1,a,1714028400000
 
  res=>(1,a,1714028400000,-3001)
  (1,a,1714028400000,-3001)
  当前的数据ID为=>1,currentMaxTimestamp=>1714028400000
  下发的 Watermark 为=>1714028396999
 
  1,b,1714028410000
 
  res=>(1,b,1714028410000,1714028396999)
  (1,b,1714028410000,1714028396999)
  当前的数据ID为=>1,currentMaxTimestamp=>1714028410000
  下发的 Watermark 为=>1714028406999
 
  1,c,1714028410001
 
  res=>(1,c,1714028410001,1714028406999)
  (1,c,1714028410001,1714028406999)
  当前的数据ID为=>1,currentMaxTimestamp=>1714028410001
  下发的 Watermark 为=>1714028407000

2、MyTimeLagWatermarkGenerator

该生成器生成的 watermark 滞后于处理时间固定量,它假定元素会在有限延迟后到达 Flink。

bash 复制代码
class MyTimeLagWatermarkGenerator implements WatermarkGenerator<_01_MyEvent> {
    // 3 秒
    private final long maxTimeLag = 3000;

    @Override
    public void onEvent(_01_MyEvent event, long eventTimestamp, WatermarkOutput output) {
        // 处理时间场景下,不需要实现 onEvent
        System.out.println("处理时间场景下,不需要实现 onEvent");
    }

    @Override
    public void onPeriodicEmit(WatermarkOutput output) {
        Watermark watermark = new Watermark(System.currentTimeMillis() - maxTimeLag);
        output.emitWatermark(watermark);
        System.out.println("下发的 Watermark 为=>" + watermark.getTimestamp());
    }
}

数据输入与输出案例

bash 复制代码
  下发的 Watermark 为=>1714284213511
 
  1,a,1714028400000
 
  res=>(1,a,1714028400000,1714284230336)
  (1,a,1714028400000,1714284230336)
  处理时间场景下,不需要实现 onEvent
  下发的 Watermark 为=>1714284230540
 
  1,b,1714028410000
 
  res=>(1,b,1714028410000,1714284254960)
  (1,b,1714028410000,1714284254960)
  处理时间场景下,不需要实现 onEvent
  下发的 Watermark 为=>1714284255166
 
  1,c,1714028410001
 
  res=>(1,c,1714028410001,1714284266639)
  (1,c,1714028410001,1714284266639)
  处理时间场景下,不需要实现 onEvent
  下发的 Watermark 为=>1714284266846

3、完整测试用例

bash 复制代码
import org.apache.flink.api.common.eventtime.*;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.tuple.Tuple4;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.ProcessFunction;
import org.apache.flink.util.Collector;

public class _01_MyWaterMarkWatermarkGeneratorPeriodic {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        // 设置水位线生成的时间间隔
        env.getConfig().setAutoWatermarkInterval(2000L);

        DataStreamSource<String> source = env.socketTextStream("localhost", 8888);
        source.map(new MapFunction<String, _01_MyEvent>() {
                    @Override
                    public _01_MyEvent map(String value) throws Exception {
                        String[] fields = value.split(",");
                        return new _01_MyEvent(Integer.parseInt(fields[0])
                                , fields[1]
                                , Long.parseLong(fields[2]));
                    }
                    // 分配水位线策略
                }).assignTimestampsAndWatermarks(new WatermarkStrategy<_01_MyEvent>() {
                    @Override
                    public WatermarkGenerator<_01_MyEvent> createWatermarkGenerator(WatermarkGeneratorSupplier.Context context) {
//                        return new MyBoundedOutOfOrdernessGenerator();
                        return new MyTimeLagWatermarkGenerator();
                    }
                    // 分配时间戳字段
                }.withTimestampAssigner(new SerializableTimestampAssigner<_01_MyEvent>() {
                    @Override
                    public long extractTimestamp(_01_MyEvent element, long recordTimestamp) {
                        return element.getEventTime();
                    }
                }))
                .process(new ProcessFunction<_01_MyEvent, Tuple4<Integer,String,Long,Long>>() {
                    @Override
                    public void processElement(_01_MyEvent value, ProcessFunction<_01_MyEvent, Tuple4<Integer, String, Long, Long>>.Context ctx, Collector<Tuple4<Integer, String, Long, Long>> out) throws Exception {
                        Tuple4<Integer, String, Long, Long> res = new Tuple4<>(value.getId(), value.getName(), value.getEventTime(), ctx.timerService().currentWatermark());
                        System.out.println("res=>"+res);
                        out.collect(res);
                    }
                })
                .print();

        env.execute();
    }
}

用到的 pojo 类

bash 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class _01_MyEvent implements Serializable {
    private Integer id;
    private String name;
    private Long eventTime;
}
相关推荐
CHICX12292 分钟前
【Hadoop】改一下core-site.xml和hdfs-site.xml配置就可以访问Web UI
xml·大数据·hadoop
权^35 分钟前
MySQL--聚合查询、联合查询、子查询、合并查询(上万字超详解!!!)
大数据·数据库·学习·mysql
bin91535 小时前
【EXCEL数据处理】000010 案列 EXCEL文本型和常规型转换。使用的软件是微软的Excel操作的。处理数据的目的是让数据更直观的显示出来,方便查看。
大数据·数据库·信息可视化·数据挖掘·数据分析·excel·数据可视化
极客先躯8 小时前
Hadoop krb5.conf 配置详解
大数据·hadoop·分布式·kerberos·krb5.conf·认证系统
2301_7869643610 小时前
3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例
java·大数据·数据库·分布式·hbase
matlabgoodboy11 小时前
“图像识别技术:重塑生活与工作的未来”
大数据·人工智能·生活
happycao12311 小时前
Flink 03 | 数据流基本操作
大数据·flink
Neituijunsir12 小时前
2024.09.22 校招 实习 内推 面经
大数据·人工智能·算法·面试·自动驾驶·汽车·求职招聘
Data 31714 小时前
Hive数仓操作(十一)
大数据·数据库·数据仓库·hive·hadoop
qtj-00115 小时前
普通人在刚开始做副业时要注意哪些细节?
大数据·微信·新媒体运营·创业创新