Flink 状态编程(五)映射状态(MapState)案例

文章目录

映射状态的用法和 Java 中的 HashMap 很相似。在这里我们可以通过 MapState 的使用来探索一下窗口的底层实现,也就是我们要用映射状态来完整模拟窗口的功能。这里我们模拟一个滚动窗口。我们要计算的是每一个 url 在每一个窗口中的 pv 数据。我们之前使用增量聚合和全窗口聚合结合的方式实现过这个需求。这里我们用 MapState 再来实现一下。

需求:定义一个滚动窗口十秒钟,在这个10秒中之内的所有数据,按照url做一个划分,统计出每个url,每一个页面被点击的次数

代码如下:

public class FakeWindowExample {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        /**
         * 定义一个滚动窗口十秒钟,在这个10秒中之内的所有数据,按照url做一个划分,统计出每个url,每一个页面被点击的次数
         */
        SingleOutputStreamOperator<Event> stream = env.addSource(new ClickSource())
                .assignTimestampsAndWatermarks(
                        WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO)
                                .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                                    @Override
                                    public long extractTimestamp(Event element, long recordTimestamp) {
                                        return element.timestamp;
                                    }
                                })
                );

        stream.print("input");

        stream.keyBy(data -> data.url)
                .process(new FakeWindowResult(10000L))
                .print();

        env.execute();
    }

    //实现自定义的keyedProcessFunction
    public static class FakeWindowResult extends KeyedProcessFunction<String,Event,String>{

        //定义窗口大小
        private Long windowSize;

        public FakeWindowResult(Long windowSize) {
            this.windowSize = windowSize;
        }

        //定义状态,用来保存每个窗口中统计的count值
        MapState<Long,Long> windowUrlCountMapState; //时间戳和个数

        @Override
        public void open(Configuration parameters) throws Exception {
            //获取运行上下文
            windowUrlCountMapState = getRuntimeContext().getMapState(new MapStateDescriptor<Long, Long>("window-count",Long.class,Long.class));
        }

        @Override
        public void processElement(Event value, KeyedProcessFunction<String, Event, String>.Context ctx, Collector<String> out) throws Exception {
            //每来一条数据,根据时间戳判断属于那个窗口(窗口分配器)
           Long windowStart = value.timestamp / windowSize * windowSize;
           Long windowEnd = windowStart + windowSize;

            //注册 end - 1 的定时器
            ctx.timerService().registerEventTimeTimer(windowEnd-1);

            //更新状态,进行增量聚合
            if(windowUrlCountMapState.contains(windowStart)){
                Long count = windowUrlCountMapState.get(windowStart);
                windowUrlCountMapState.put(windowStart,count+1);
            }else{
                windowUrlCountMapState.put(windowStart,1L);
            }
        }

        @Override
        public void onTimer(long timestamp, KeyedProcessFunction<String, Event, String>.OnTimerContext ctx, Collector<String> out) throws Exception {
            //定时器触发时输出计算结果
            Long windowEnd = timestamp + 1;
            Long windowStart = windowEnd - windowSize;

            Long count = windowUrlCountMapState.get(windowStart);

            out.collect("窗口:"+new Timestamp(windowStart) + " ~ " + new Timestamp(windowEnd)
                +" url: " + ctx.getCurrentKey()
                    + " count: " + count
            );

            //模拟窗口的关闭,清空map状态中的值
            windowUrlCountMapState.remove(windowStart);
        }
    }
}

Gitee完整代码展示

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要获取MapState中的所有数据,可以使用FlinkStatefulStreamProcessing功能中提供的MapState.iterator()方法。该方法将返回一个迭代器,可以遍历MapState中的所有键值对。具体代码如下: ``` import org.apache.flink.api.common.functions.RichFlatMapFunction; import org.apache.flink.api.common.state.MapState; import org.apache.flink.api.common.state.MapStateDescriptor; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.configuration.Configuration; import org.apache.flink.util.Collector; public class MyFlatMapFunction extends RichFlatMapFunction<Tuple2<String, String>, Tuple2<String, String>> { private transient MapState<String, String> mapState; @Override public void open(Configuration config) { MapStateDescriptor<String, String> descriptor = new MapStateDescriptor<>("myMapState", String.class, String.class); mapState = getRuntimeContext().getMapState(descriptor); } @Override public void flatMap(Tuple2<String, String> input, Collector<Tuple2<String, String>> out) throws Exception { mapState.put(input.f0, input.f1); //获取MapState中的所有数据 for (Map.Entry<String, String> entry : mapState.iterator()) { out.collect(new Tuple2<>(entry.getKey(), entry.getValue())); } } } ``` 在上面的代码中,我们定义了一个MapStateDescriptor,用于描述MapState的名称和键值对的数据类型。然后在open()方法中,使用getRuntimeContext().getMapState(descriptor)方法获取MapState的实例。在flatMap()方法中,我们首先向MapState中添加了一个新的键值对,然后使用mapState.iterator()方法获取迭代器,遍历MapState中的所有键值对,并将它们发送到下游算子。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值