1. Introduction to Timer
Timer (Timer) is a mechanism provided by Flink Streaming API to sense and utilize processing time/event time changes.
The most common place to use Timer is KeyedProcessFunction. We register the Timer in its processElement() method, and then override its onTimer() method as the callback logic when the Timer is triggered. According to different time characteristics:
(1) Processing time -call Context.timerService().registerProcessingTimeTimer() to register; onTimer() is triggered when the system timestamp reaches the timestamp set by Timer.
(2) Event time -call Context.timerService().registerEventTimeTimer() to register; onTimer() is triggered when the internal watermark of Flink reaches or exceeds the timestamp set by the Timer.
Two, use demo
The demo function is to use mapState for wordCount and Timer to periodically clear the state every 2 seconds
(1) Program entry
package testOntimer;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/**
* @程序功能:读取文件,进行wordCount,利用state测试onTimer定时器
* @author gaoj
* @Created_in 2020-12-08
*/
public class Driver {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env
.addSource(new Source())
.flatMap(new Map())
.keyBy(t -> t._1)
.process(new Process())
.print();
env.execute();
}
}
(2) Program data source
package testOntimer;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.concurrent.TimeUnit;
public class Source extends RichSourceFunction<String> {
private Boolean isRunning = true;
@Override
public void run(SourceContext<String> ctx) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\test.txt"));
while (isRunning){
String line = bufferedReader.readLine();
if(StringUtils.isNotBlank(line)){
ctx.collect(line);
}
TimeUnit.SECONDS.sleep(10);
}
}
@Override
public void cancel() {
isRunning = false;
}
}
(3) Data source conversion
package testOntimer;
import org.apache.flink.api.common.functions.RichFlatMapFunction;
import org.apache.flink.util.Collector;
import scala.Tuple2;
public class Map extends RichFlatMapFunction<String, Tuple2<String,Integer>> {
@Override
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
String[] split = value.split(",");
for (String s : split) {
out.collect(new Tuple2<>(s,1));
}
}
}
(4) Perform wordCount
package testOntimer;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import scala.Tuple2;
import java.util.Calendar;
public class Process extends KeyedProcessFunction<String, Tuple2<String,Integer> ,Tuple2<String,Integer>> {
private transient MapState<String,Integer> mapState;
private transient ValueState<Integer> valueState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
MapStateDescriptor<String,Integer> mapStateDescriptor = new MapStateDescriptor<>("valueStateDesc",
TypeInformation.of(new TypeHint<String>() {}),
TypeInformation.of(new TypeHint<Integer>() {}));
mapState = getRuntimeContext().getMapState(mapStateDescriptor);
ValueStateDescriptor<Integer> ValueStateDescriptor = new ValueStateDescriptor<>("phoneCount",
TypeInformation.of(new TypeHint<Integer>() {
}));
valueState=getRuntimeContext().getState(ValueStateDescriptor );
}
@Override
public void processElement(Tuple2<String,Integer> value, Context ctx, Collector<Tuple2<String, Integer>> out) throws Exception {
if (valueState.value()==null){
ctx.timerService().registerProcessingTimeTimer(System.currentTimeMillis()+2000);
}
int i = mapState.contains(value._1) ? mapState.get(value._1) : 0;
int i1 = i + 1;
mapState.put(value._1,i1);
out.collect(new Tuple2<>(value._1,i1));
}
@Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<Tuple2<String, Integer>> out) throws Exception {
mapState.clear();
valueState.clear();
}
@Override
public void close() throws Exception {
super.close();
}
}