有界流:
不知道有没有这个概念,我这里用它表示以流处理的方式读取的批数据,比如streamExecutionEnvironment.fromCollection(...)
其实这种做法或需求是比较奇怪的,要用流处理,但读的却是批数据,最好用流处理api处理流数据,用批处理api处理批数据。
我这里之所以有这样反人类的设计,是出于批处理一次性读取全部数据有可能会内存溢出的情况下考虑的。想通过流的方式读取批数据来解决。但是后面想了想,这好像简直是一厢情愿。批量读取数据后交给流处理api,这只是处理的过程按流的方式进行,但读数据还是一次性读取的,并不是流的方式一条条读(不过这只是我个人的分析,没有找到相关的资料,也没有验证),所以,这种想法太愚蠢。
虽然这种做法是愚蠢的,是不推荐使用的。但可能有朋友也跟我一样“愚蠢”,因此这里记录一下这种方式遇到的问题,供朋友参考。
上代码:
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
List<BatchReduce.Deposit> list = new ArrayList<>();
list.add(new BatchReduce.Deposit(1,100));
list.add(new BatchReduce.Deposit(2,100));
list.add(new BatchReduce.Deposit(5,100));
list.add(new BatchReduce.Deposit(4,100));
list.add(new BatchReduce.Deposit(1,50));
list.add(new BatchReduce.Deposit(2,60));
list.add(new BatchReduce.Deposit(1,60));
list.add(new BatchReduce.Deposit(1,50));
DataStreamSource<BatchReduce.Deposit> source = env.fromCollection(list);
SingleOutputStreamOperator<BatchReduce.Deposit> sum = source.keyBy(new KeySelector<BatchReduce.Deposit, Integer>() {
@Override
public Integer getKey(BatchReduce.Deposit value) throws Exception {
return value.getStudentID();
}
}).timeWindow(Time.seconds(1))
.sum("money");
sum.print();
env.execute();
}
代码很简单,就是要根据studentID分组,然后开1s的时间窗对money进行聚合。
但现象是压根没有数据输出。这里数据量太小,当数据量大的时候,更好测试。
分析原因,是因为这种方式读的数据是没有时间概念的,是一次性批量读取的。可能数据还没有进入窗口,或还没有达到触发窗口的条件时,整个程序就结束了。因此不会输出。(这可以在读取大数据量的时候,逐步调大时间窗口大小来测试)
因此,这种读取批数据后开时间窗进行计算的方式是绝对不可取的。
但如果不加时间直接聚合,则没有问题。或者加计数窗countwindow,但这种需要解决最后一个窗口数据不足时如何触发,不然也会由于程序结束导致丢最后一个窗口的数据。