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
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值