![](/img/trans.png)
[英]Cannot infer type-variable(s) R in 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 進行重復數據刪除的另一個問題是它們對管道施加的延遲,以及用於最小化該延遲的變通方法。
這就是為什么我更喜歡使用RichFlatMapFunction
或KeyedProcessFunction
實現重復數據刪除。 像這樣的東西會比窗口表現得更好:
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.