我有一个使用windows的flink流作业。
我的目标是在一分钟之内将记录按其内部id
进行分组,并仅按id
逐条记录最新记录。
我想出了两种可能的方法:
使用reduce()
stream.keyBy(Record::getId)
.window(TumblingProcessingTimeWindows.of(Time.seconds(60)))
.reduce((rec1, rec2) -> rec2);
这很好用,但似乎很浪费,因为它需要每个和每个记录。
使用process()
stream.keyBy(Record::getId)
.window(TumblingProcessingTimeWindows.of(Time.seconds(60)))
.process(new ProcessWindowFunction<Record, Object, Long, TimeWindow>() {
@Override
public void process(Long aLong, Context context, Iterable<Record> iterable, Collector<Object> collector) throws Exception {
Record last = null;
for (Record rec : iterable) {
if (last == null || last.getTimestamp() < rec.getTimestamp()) {
last = rec;
}
}
collector.collect(last);
}
});
这也可以正常工作。我曾预计它会更快,但它不是(与解决方案1大致相同)。
您能推荐一种更好的方法吗?
答案 0 :(得分:0)
您的解决方案1.似乎是这里的最佳方法。
关于您的评论:
这很好用,但似乎浪费了,因为每条记录都需要调用它。
问题是您不知道哪个记录将是最后一个。因此,您始终需要存储最后看到的记录。由于ReduceFunction
的结果存储在状态中(用于方法的下一次评估或将其作为结果返回),所以这正是这里发生的情况。
您的解决方案2实际上(从存储/内存的角度来看)效率较低。它会记住在一分钟内到达的所有记录,并在评估窗口时遍历所有记录。相反,解决方案1.仅存储一个值(最后一次函数求值的结果)。
您可以使用常规的ProcessFunction
和计时器来实现解决方案,但是,我认为这不会比window + ReduceFunction
快得多。而且,这将需要更多代码。