場景:
不使用 Flink 提供的 sum() 方法,使用 KeyedState 完成對單詞分組求和計算操作。
代碼:
/**
* TODO 不使用 Flink 提供的sum()方法,對單詞進行分組求和計算。
*
* @author liuzebiao
* @Date 2020-2-17 11:42
*/
public class KeyedStateDemo {
public static void main(String[] args) throws Exception {
//1.創建一個 flink steam 程序的執行環境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//2.使用StreamExecutionEnvironment創建DataStream
DataStreamSource<String> lines = env.socketTextStream( "localhost", 8888);
//Transformation(s) 對數據進行處理操作
SingleOutputStreamOperator<Tuple2<String, Integer>> wordAndOne = lines.map(new MapFunction<String, Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> map(String word) {
//將每個單詞與 1 組合,形成一個元組
return Tuple2.of(word, 1);
}
});
//進行分組聚合(keyBy:將key相同的分到一個組中)
KeyedStream<Tuple2<String, Integer>, Tuple> keyedStream = wordAndOne.keyBy(0);
/** 使用 KeyedState 通過中間狀態求和 ----- start ----**/
SingleOutputStreamOperator<Tuple2<String, Integer>> summed = keyedStream.map(new RichMapFunction<Tuple2<String, Integer>, Tuple2<String, Integer>>() {
//狀態數據不參與序列化,添加 transient 修飾
private transient ValueState<Integer> valueState;
@Override
public void open(Configuration parameters) throws Exception {
//獲取 KeyedState 數據
ValueStateDescriptor stateDescriptor = new ValueStateDescriptor("sum-key-state", Types.TUPLE(Types.STRING, Types.INT));
valueState = getRuntimeContext().getState(stateDescriptor);
}
@Override
public Tuple2<String, Integer> map(Tuple2<String, Integer> tuple2) throws Exception {
//輸入的單詞
String word = tuple2.f0;
//輸入的次數
Integer count = tuple2.f1;
//根據State獲取中間數據
Integer historyVal = valueState.value();
//根據State中間數據,進行累加
if (historyVal != null) {
historyVal += count;
//累加後,更新State數據
valueState.update(historyVal);
} else {
valueState.update(count);
}
return Tuple2.of(word,valueState.value());
}
});
/** 使用 KeyedState 通過中間狀態求和 ----- end ----**/
//Transformation 結束
//3.調用Sink (Sink必須調用)
summed.print();
//啓動(這個異常不建議try...catch... 捕獲,因爲它會拋給上層flink,flink根據異常來做相應的重啓策略等處理)
env.execute("KeyedStateDemo");
}
}