如何在Apache Flink中为会话窗口分配ID?
最终,我想在会话窗口打开时以一个会话窗口ID一对一地丰富事件(我不想等到窗口关闭后才发出丰富事件)。
我试图使用AggregateFunction来做到这一点,但是我认为merge()并不像我期望的那样工作。它似乎是用于合并窗口,而不是用于合并窗格(触发触发)。在我的管道中似乎从未调用过它。因此,似乎触发器之间没有共享状态!
会话窗口ID将是第一个事件落入窗口的时间戳(由于无保证的排序,这可能意味着某些事件可能会以较早的时间戳落入同一会话窗口中-我很好与此)。
public class FooSessionState {
private Long sessionCreationTime;
private FooMatch lastMatch;
}
/**
* Aggregator that assigns session ids to elements of a session window
*/
public class SessionIdAssigner implements
AggregateFunction<FooMatch, FooSessionState, FooSessionEvent> {
static final long serialVersionUID = 0L;
@Override
public FooSessionState createAccumulator() {
return new FooSessionState();
}
@Override
public FooSessionState add(FooMatch value, FooSessionState sessionState) {
if (sessionState.getSessionCreationTime() == null) {
sessionState.setSessionCreationTime(value.getReport().getTimestamp());
}
sessionState.setLastMatch(value);
return sessionState;
}
@Override
public FooSessionEvent getResult(FooSessionState accumulator) {
FooSessionEvent sessionEvent = new FooSessionEvent();
sessionEvent.setFooMatch(accumulator.getLastMatch());
sessionEvent.setSessionCreationTime(accumulator.getSessionCreationTime());
return sessionEvent;
}
@Override
public FooSessionState merge(FooSessionState a, FooSessionState b) {
if ( a.getSessionCreationTime() != null) {
b.setSessionCreationTime(a.getSessionCreationTime());
}
return b;
}
}
我的计划是按如下方式使用它:
stream.keyBy(new FooMatchKeySelector())
.window(EventTimeSessionWindows.withGap(Time.milliseconds(config.getFooSessionWindowTimeout())))
.trigger(PurgingTrigger.of(CountTrigger.of(1L)))
.aggregate(new SessionIdAssigner())
答案 0 :(得分:0)
我认为会话窗口不适合您要实现的目标。它们的设计目的是汇总每个会话的事件,但不能丰富每个事件,即,它们计算结果并在关闭窗口时发出结果。如您所注意到的,会话窗口通过为每个事件创建一个新窗口并合并重叠的窗口来工作。之所以选择这种设计,是因为事件可能会无序到达。因此,可能有两个窗口,以后通过桥接事件将它们连接起来。
我建议使用ProcessFunction
来实现逻辑,该逻辑收集事件并将事件按时间戳排序。收到水印后,它将发出具有正确会话ID的所有收集的事件。因此,您仅将两个水印之间的事件保持在状态中。除了这些事件之外,您还需要保留最后发出的事件的时间戳和最后发出的会话ID,以执行正确的会话化。