簡體   English   中英

Flink 重復數據刪除和 processWindowFunction

[英]Flink deduplication and processWindowFunction

我正在創建一個管道,其中輸入是包含時間戳字段的 json 消息,用於設置 eventTime。 問題在於某些記錄可能會延遲到達或在系統中重復,這種情況需要管理; 為避免重復,我嘗試了以下解決方案:

                .assignTimestampsAndWatermarks(new RecordWatermark()
                        .withTimestampAssigner(new ExtractRecordTimestamp()))
                .keyBy(new MetricGrouper())
                .window(TumblingEventTimeWindows.of(Time.seconds(60)))
                .trigger(ContinuousEventTimeTrigger.of(Time.seconds(3)))
                .process(new WindowedFilter())
                .keyBy(new MetricGrouper())
                .window(TumblingEventTimeWindows.of(Time.seconds(180)))
                .trigger(ContinuousEventTimeTrigger.of(Time.seconds(15)))
                .process(new WindowedCountDistinct())
                .map((value) -> value.toString());

其中第一個窗口操作是根據保存在集合中的時間戳來過濾記錄,如下所示:

public class WindowedFilter extends ProcessWindowFunction<MetricObject, MetricObject, String, TimeWindow> {
    HashSet<Long> previousRecordTimestamps = new HashSet<>();

    @Override
    public void process(String s, Context context, Iterable<MetricObject> inputs, Collector<MetricObject> out) throws Exception {
        String windowStart = DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochMilli(context.window().getStart()));
        String windowEnd = DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochMilli(context.window().getEnd()));
        log.info("window start: '{}', window end: '{}'", windowStart, windowEnd);

        Long watermark = context.currentWatermark();
        log.info(inputs.toString());
        for (MetricObject in : inputs) {
            Long recordTimestamp = in.getTimestamp().toEpochMilli();
            if (!previousRecordTimestamps.contains(recordTimestamp)) {
                log.info("timestamp not contained");
                previousRecordTimestamps.add(recordTimestamp);
                out.collect(in);
            }
        }
    }

這個解決方案有效,但我感覺我沒有考慮一些重要的事情,或者可以以更好的方式完成。

使用 windows 進行重復數據刪除的一個潛在問題是 Flink 的 DataStream API 中實現的 windows 始終與 epoch 對齊。 這意味着,例如,發生在 11:59:59 的事件和發生在 12:00:01 的重復事件將被放置到不同的分鍾窗口中。

但是,在您的情況下,您擔心的重復項似乎也帶有相同的時間戳。 在這種情況下,您所做的將產生正確的結果,只要您不擔心水印會產生延遲事件。

使用 windows 進行重復數據刪除的另一個問題是它們對管道施加的延遲,以及用於最小化該延遲的變通方法。

這就是為什么我更喜歡使用RichFlatMapFunctionKeyedProcessFunction實現重復數據刪除。 像這樣的東西會比窗口表現得更好:

private static class Event {
  public final String key;
}

public static void main(String[] args) throws Exception {
  StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
  
  env.addSource(new EventSource())
    .keyBy(e -> e.key)
    .flatMap(new Deduplicate())
    .print();
  
  env.execute();
}

public static class Deduplicate extends RichFlatMapFunction<Event, Event> {
  ValueState<Boolean> seen;

  @Override
  public void open(Configuration conf) {
    StateTtlConfig ttlConfig = StateTtlConfig
      .newBuilder(Time.minutes(1))
      .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
      .cleanupFullSnapshot()
      .build();
    ValueStateDescriptor<Boolean> desc = new ValueStateDescriptor<>("seen", Types.BOOLEAN);
    desc.enableTimeToLive(ttlConfig);
    seen = getRuntimeContext().getState(desc);
  }

  @Override
  public void flatMap(Event event, Collector<Event> out) throws Exception {
    if (seen.value() == null) {
      out.collect(event);
      seen.update(true);
    }
  }
}

這里的流正在通過key進行重復數據刪除,並且在一分鍾后自動清除所涉及的狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM