目录
值状态(ValueState)
Flink状态保留一个值,例如Integer、Long类型。
常用的方法如下
value() // 获取当前状态的值
update() // 更新当前状态的值
下面实现一个简单案例,来加深理解。watersensor对象的 ts 表示水位值,现在需要找到连续两条水位值相差大于10的数据,这时候就可以用值状态来存储上一条水位值。
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env
.socketTextStream("node1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy
.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((value,ts) -> value.getTs()*1000L)
);
sensorDS
.keyBy(value -> value.getId())
.process(new KeyedProcessFunction<String, WaterSensor, String>() {
// TODO 1.定义状态
ValueState<Integer> lastValueState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
// TODO 2.在open方法中,初始化状态
// 状态描述器两个参数:第一个参数,起个名字,不重复;第二个参数,存储的类型
lastValueState = getRuntimeContext().getState(new ValueStateDescriptor<Integer>("valueState", Types.INT));
}
@Override
public void processElement(WaterSensor waterSensor, Context context, Collector<String> collector) throws Exception {
// 取出上一条水位数据(存储在值状态中)
int lastVc = lastValueState.value() == null ? 0 : lastValueState.value();
Integer vc = waterSensor.vc;
if(Math.abs(lastVc-vc) > 10){
collector.collect("传感器:" + context.getCurrentKey() + "当前水位值" + vc + ",上一条水位值" + lastVc + "相差超过10");
}
lastValueState.update(vc);
}
})
.print();
env.execute();
}
由于使用按键分区状态,可以看到,s2,11,11这条数据,他的上一条tc应该为null,值状态也为空,代码中手动赋值为0,因此这条数据也被打印输出。因此,也证明了每一个key都有一个状态。
列表状态(ListState)
将需要保存的值,以列表的形式存储起来。
常用方法如下
ListState.get(); //取出 list状态 本组的数据,是一个Iterable
ListState.add(); // 向 list状态 本组 添加一个元素
ListState.addAll(); // 向 list状态 本组 添加多个元素
ListState.update(); // 更新 list状态 本组数据(覆盖)
ListState.clear(); // 清空List状态 本组数据
下面实现一个案例,输出每个传感器(id)最高的三个水位值。
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env
.socketTextStream("node1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy
.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((value,ts) -> value.getTs()*1000L)
);
// 输出每个传感器最高的3个水位值
sensorDS.keyBy(value -> value.getId())
.process(new KeyedProcessFunction<String, WaterSensor, String>() {
ListState<Integer> listState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
listState = getRuntimeContext().getListState(new ListStateDescriptor("vclistState", Types.INT));
}
@Override
public void processElement(WaterSensor waterSensor, Context context, Collector<String> collector) throws Exception {
// 1、来一条数据存储一条
listState.add(waterSensor.vc);
// 2、从list状态拿出来(Iterable), 拷贝到一个List中,排序, 只留3个最大的
Iterable<Integer> iter = listState.get();
List<Integer> list = new ArrayList<>();
for (Integer vc : iter) {
list.add(vc);
}
// 降序,后 - 前
list.sort((o1,o2) -> (o2-o1));
// 3、只保留最大的3个(list中的个数一定是连续变大,一超过3就立即清理即可)
if(list.size() > 3){
list.remove(3);