Apache flink 如何根据其密钥配置Flink窗口时间

Apache flink 如何根据其密钥配置Flink窗口时间,apache-flink,Apache Flink,不同类型的项到达一个源中,我根据其“类型”将它们划分到不同的窗口中。现在,每个类型的窗口必须配置自己的发射超时,而不是一个.byKey(“type”)窗口(TumblingProcessingTimeWindows.of(Time.seconds(1)))。允许延迟(Time.seconds(5)) 例如: {{“1型”,5m},{“2型”,10m},{“3型”,1m} 因此,添加到type-1键控窗口的元素的发射时间为5分钟,类似地type-2的发射时间为10分钟,依此类推 我可以通过在Key

不同类型的项到达一个源中,我根据其“类型”将它们划分到不同的窗口中。现在,每个
类型的
窗口必须配置自己的发射超时,而不是一个
.byKey(“type”)窗口(TumblingProcessingTimeWindows.of(Time.seconds(1)))。允许延迟(Time.seconds(5))

例如: {{“1型”,5m},{“2型”,10m},{“3型”,1m}

因此,添加到
type-1
键控窗口的元素的发射时间为5分钟,类似地
type-2
的发射时间为10分钟,依此类推

我可以通过在
KeyedProcessFunction
RegisterProcessingTimer
中维护一个带有时间列表的状态,并为键配置超时来实现这一点


但是,我不需要管理状态和元素,如何使用
窗口
?我尝试了自定义
触发器,但无法明确地使其工作。

我认为您可以使用GlobalWindows以及自定义触发器(可能还有自定义逐出器)来实现这一点。另一种方法可能是使用自定义窗口赋值器


一般来说,我不鼓励深入研究自定义窗口API,因为最终的解决方案很难理解。

我在下面发布了我的自定义
触发器方法的代码修复。我没有使用@David建议的
逐出器
,而是在
onProcessingTime
中使用了FIRE\u和\u PURGE。这种方法似乎已经在少数场景中进行了测试

插槽配置

private static final Map<String, Long> eventSlots = new HashMap<>();

static {
    eventSlots.put("type22", 30000l);
    eventSlots.put("type12", 15000l);
    eventSlots.put("type9", 10000l);
    eventSlots.put("type2", 20000l);
    eventSlots.put("type7", 13000l);
}
private static final Map eventSlots=new HashMap();
静止的{
eventSlots.put(“22型”,30000l);
eventSlots.put(“12型”,15000l);
eventSlots.put(“类型9”,10000l);
eventSlots.put(“类型2”,20000l);
eventSlots.put(“7型”,13000l);
}
处理代码

SingleOutputStreamOperator<Event> sourceStream = ...

someSourceStream
.keyBy("type")
.window(GlobalWindows.create())
.trigger(new Trigger<Event, GlobalWindow>() {

 @Override
 public TriggerResult onElement(Event element, long timestamp, GlobalWindow window,
         TriggerContext ctx) throws Exception {
     ctx.registerProcessingTimeTimer(ctx.getCurrentProcessingTime() + eventSlots.get(element.getType()));
     return TriggerResult.CONTINUE;
 }

 @Override
 public TriggerResult onProcessingTime(long time, GlobalWindow window, TriggerContext ctx)
         throws Exception {
     return TriggerResult.FIRE_AND_PURGE;
 }

 @Override
 public TriggerResult onEventTime(long time, GlobalWindow window, TriggerContext ctx)
         throws Exception {
     return TriggerResult.CONTINUE;
 }

 @Override
 public void clear(GlobalWindow window, TriggerContext ctx) throws Exception {
     ctx.deleteProcessingTimeTimer(window.maxTimestamp());
 }

}).process(new ProcessWindowFunction<Event, Events, Tuple, Context> () {
     @Override
     public void process(Tuple arg0,
         ProcessWindowFunction<Event, Events, Tuple, GlobalWindow>.Context ctx,
         Iterable<Event> arg2, Collector<Event> arg3) throws Exception {
       List<Event> events = new ArrayList<>();
       arg2.forEach(events::add);
       arg3.collect(new Events(events));
});
SingleOutputStreamOperator sourceStream=。。。
someSourceStream
.keyBy(“类型”)
.window(GlobalWindows.create())
.trigger(新触发器(){
@凌驾
public TriggerResult OneElement(事件元素、长时间戳、全局窗口、,
TriggerContext(ctx)引发异常{
registerProcessingTimer(ctx.getCurrentProcessingTime()+eventSlots.get(element.getType());
返回TriggerResult.CONTINUE;
}
@凌驾
public TriggerResult on ProcessingTime(长时间、全局窗口、TriggerContext ctx)
抛出异常{
返回TriggerResult.FIRE\u和\u PURGE;
}
@凌驾
公共TriggerResult onEventTime(长时间、全局窗口、TriggerContext ctx)
抛出异常{
返回TriggerResult.CONTINUE;
}
@凌驾
公共无效清除(GlobalWindow窗口,TriggerContext ctx)引发异常{
ctx.deleteProcessingTimer(window.maxTimestamp());
}
}).process(新的ProcessWindowFunction(){
@凌驾
公共无效进程(元组arg0,
ProcessWindowFunction.Context ctx,
Iterable arg2、收集器arg3)引发异常{
列表事件=新建ArrayList();
arg2.forEach(事件::add);
arg3.收集(新事件(事件));
});

我在回答中分享的示例----如果您最终使用
KeyedProcessFunction
,可能会有所帮助。这些每键计时是静态的(即在编译时已知的)?至少你需要一个自定义窗口分配程序,但是如果每个键的计时信息不是静态的,并且需要保持在flink状态,我不知道如何做到这一点,并使其可供窗口分配程序使用。是的,可能是FIRE_and_PURGE就足够了,你不需要自定义驱逐程序。我更新了我的答案。如果只是有一个h除了静态窗口大小的事件类型之外,您还可以按事件类型分割流,并在每个子流上应用一个普通窗口。