有界流:
不知道有沒有這個概念,我這裏用它表示以流處理的方式讀取的批數據,比如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,但這種需要解決最後一個窗口數據不足時如何觸發,不然也會由於程序結束導致丟最後一個窗口的數據。