[英]Using Flink window and fold function, element missing?
當我嘗試使用 window 和 fold 函數聚合元素時,某些元素在聚合時丟失了。 使用來自 Kafka 的元素(value:0, value:1, value:2, value:3)
並將它們聚合為奇數和偶數值。
輸出是:
{even=[0, 2, 4], odd=[1, 3]}
{even=[6, 8], odd=[5, 7, 9]}
{even=[14, 16, 18], odd=[15, 17]}
{even=[20, 22], odd=[19, 21, 23]}
{even=[24, 26, 28], odd=[25, 27]}
10-13 之間的數字缺失,這發生在一組隨機數字上。 有人可以建議下面的代碼遺漏了什么,我如何確保處理所有元素?
public static class Splitter implements FlatMapFunction<String,
Tuple3<String, String, List<String>>{
private static final long serialVersionUID = 1L;
@Override
public void flatMap(String value, Collector<Tuple3<String, String,
List<String>>out) throws Exception {
String[] vals = value.split(":");
if(vals.length 1 && Integer.parseInt(vals[1]) % 2 == 0){
out.collect(new Tuple3<String, String, List<String>>
("test","even", Arrays.asList(vals[1])));
}else{
out.collect(new Tuple3<String, String, List<String>>
("test","odd", Arrays.asList(vals[1])));
}
}
}
DataStream<Map<String, List<String>>streamValue =
kafkaStream.flatMap(new Splitter()).keyBy(0)
.window(TumblingEventTimeWindows.of(Time.milliseconds(3000))).
trigger(CustomizedCountTrigger.of(5L))//.trigger(CountTrigger.of(2))
.fold(new HashMap<String, List<String>>(), new
FoldFunction<Tuple3<String, String, List<String>>, Map<String,
List<String>>>() {
private static final long serialVersionUID = 1L;
@Override
public Map<String, List<String>fold(Map<String,
List<String>accumulator,
Tuple3<String, String, List<String>value) throws
Exception {
if(accumulator.get(value.f1) != null){
List<Stringlist = new ArrayList<>();
list.addAll(accumulator.get(value.f1));
list.addAll(value.f2);
accumulator.put(value.f1, list);
}else{
accumulator.put(value.f1, value.f2);
}
return accumulator;
}
});
streamValue.print();
env.execute("window test");
}
public class CustomizedCountTrigger<W extends Windowextends
Trigger<Object, W{
private static final long serialVersionUID = 1L;
private final long maxCount;
private final ReducingStateDescriptor<LongstateDesc =
new ReducingStateDescriptor<>("count", new Sum(),
LongSerializer.INSTANCE);
private CustomizedCountTrigger(long maxCount) {
this.maxCount = maxCount;
}
@Override
public TriggerResult onElement(Object element, long timestamp, W window,
TriggerContext ctx) throws Exception {
ReducingState<Longcount = ctx.getPartitionedState(stateDesc);
count.add(1L);
if (count.get() >= maxCount) {
count.clear();
return TriggerResult.FIRE_AND_PURGE;
}
return TriggerResult.CONTINUE;
}
@Override
public TriggerResult onProcessingTime(long time, W window,
org.apache.flink.streaming.api.windowing.triggers.Trigger.TriggerContext
ctx) throws Exception {
return TriggerResult.CONTINUE;
}
@Override
public TriggerResult onEventTime(long time, W window,
org.apache.flink.streaming.api.windowing.triggers.Trigger.TriggerContext
ctx) throws Exception {
return TriggerResult.CONTINUE;
}
@Override
public void clear(W window,
org.apache.flink.streaming.api.windowing.triggers.Trigger.TriggerContext
ctx)
throws Exception {
ctx.getPartitionedState(stateDesc).clear();
}
@Override
public String toString() {
return "CountTrigger(" + maxCount + ")";
}
public static <W extends WindowCustomizedCountTrigger<Wof(long
maxCount) {
return new CustomizedCountTrigger<>(maxCount);
}
private static class Sum implements ReduceFunction<Long{
private static final long serialVersionUID = 1L;
@Override
public Long reduce(Long value1, Long value2) throws Exception {
return value1 + value2;
}
}
}
因此,在注意到您的自定義觸發器使您使用 TumblingEventTime 窗口這一事實無關緊要之前,我開始編寫本文的第一部分,但無論如何我想包括我的原始想法,因為我不完全確定您為什么要使用 EventTime 窗口當你不使用它時。 意識到這一點后,我的回應低於原稿。
您是在單個並行還是多個並行上運行它? 我問的原因是因為如果是多並行(而且kafka主題也由多個分區組成),那么消息接收和處理的順序可能是非順序的。 這可能會導致帶有時間戳的消息導致水印提前,從而導致窗口處理消息。 然后下一條消息的事件時間在當前水印時間之前(也就是“遲到”),這將導致消息被丟棄。
例如:如果您有 20 個元素,並且每個元素的事件時間如下:
消息1:事件時間:1000 消息1:事件時間:2000 等等...
你的事件時間窗口是 5001 毫秒。
現在消息 message1 到 message9 依次通過。 第一個窗口將被處理並包含消息 1-5(消息 6 將導致窗口被處理)。 現在,如果 message11 在 message10 之前進入,它將導致處理包含消息 6-9 的窗口。 當 message10 出現時,水印已經超過 message10 的事件時間,導致它作為“延遲事件”被丟棄。
正確答案
不要使用 eventTime 窗口和自定義觸發器,而是嘗試使用 countWindow。
所以替換這個:
.window(TumblingEventTimeWindows.of(Time.milliseconds(3000))).
trigger(CustomizedCountTrigger.of(5L))//.trigger(CountTrigger.of(2))
有了這個:
.countWindow(5L)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.