计算总数并在flink中定期发出

时间:2018-04-03 17:18:13

标签: java apache-flink flink-streaming stream-processing

我有一系列关于资源的事件,如下所示:

id, type,      count
1,  view,      1
1,  download,  3
2,  view,      1
3,  view,      1
1,  download,  2
3,  view,      1

我正在尝试为每个资源生成统计信息(总计),所以如果我得到上面的流,结果应为:

id, views, downloads
1,  1,     5
2,  1,     0
3,  2,     0

现在我写了一个ProcessFunction来计算这样的总数:

public class CountTotals extends ProcessFunction<Event, ResourceTotals> {
    private ValueState<ResourceTotals> totalsState;

    @Override
    public void open(Configuration config) throws Exception {
        ValueStateDescriptor<ResourceTotals> totalsDescriptor = new ValueStateDescriptor<>("totals state", ResourceTotals.class);
        totalsDescriptor.setQueryable("resource-totals");
        totalsState = getRuntimeContext().getState(totalsDescriptor);
    }

    @Override
    public void processElement(Event event, Context ctx, Collector<ResourceTotals> out) throws Exception {
        ResourceTotals totals = totalsState.value();
        if (totals == null) {
            totals = new ResourceTotals();
            totals.id = event.id;
        }
        switch (event.type) {
            case "view":
                totals.views += event.count;
                break;
            case "download":
                totals.downloads += event.count;
        }
        totalsState.update(totals);
        out.collect(totals);
    }
}

从代码中可以看出,它会为每个事件发出一个新的ResourceTotals,但我希望每分钟发送一次总资源,而不是更频繁。

我尝试使用全局窗口和触发器(ContinuousProcessingTimeTrigger)进行实验,但无法使其工作。我遇到的问题是:

  1. 如何表达我想要窗口的最后一个事件?
  2. 如何最终存储在该全局窗口中生成的所有ResourceTotals?
  3. 任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:2)

您可以使用计时器每分钟在totalalsState中发出一次值。由于我没有在数据流中看到任何时间戳,我想你会使用处理时间计时器。

另一种方法是用TimeWindow替换ProcessFunction以及保留最后一个事件的ReduceFunction

在任何一种情况下,您都可以考虑通过ID和类型字段来键入流,这样可以简化您的状态管理。

更新:

是的,定时器是Flink检查和恢复的州的一部分。