15种实时uv实现方案系列(附源码)之二:Flink基于state实时uv统计

UVStatMultiPlans(GitHub)项目持续收集各种高性能实时uv实现方案并对各种实现方案的优缺点进行对比分析!

需求描述

消费Kafka日志行为数据,统计每分钟用户每个页面的uv访问量。

Kafka数据格式
{"userId":"c61b801e-22e7-4238-8f67-90968a40f2a7","page":"page_1","behaviorTime":1692247408129}
{"userId":"c61b801e-22e7-4238-8f67-90968a40f2a7","page":"page_2","behaviorTime":1692247408129}
代码实现

文件:UVStatPlan2.class

public class UVStatPlan2 {

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(5);
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        env.getConfig().setAutoWatermarkInterval(TimeUnit.MINUTES.toMillis(10));
        Properties kafkaProperties = new Properties();
        kafkaProperties.setProperty("bootstrap.servers", SysConst.KAFKA_BOOTSTRAP_SERVERS);
        kafkaProperties.setProperty("group.id","groupId_" + System.currentTimeMillis());
        kafkaProperties.setProperty("auto.offset.reset","latest");
        FlinkKafkaConsumer<String> consumer =
                new FlinkKafkaConsumer<String>(SysConst.KAFKA_TOPIC_NAME, new SimpleStringSchema(), kafkaProperties);
        DataStream<UserBehavior> dataStream = env.addSource(consumer).map(x -> {
            UserBehavior userBehavior = null;
            try{
                userBehavior = JsonUtil.toJavaObject(x,UserBehavior.class);
            }catch (Exception ex){
                ex.printStackTrace();
            }
            return userBehavior;
        }).assignTimestampsAndWatermarks
                (WatermarkStrategy.<UserBehavior>forMonotonousTimestamps().withTimestampAssigner((SerializableTimestampAssigner<UserBehavior>)
                        (userBehavior, l) -> userBehavior.getBehaviorTime()));
        dataStream.keyBy((KeySelector<UserBehavior, String>) UserBehavior::getPage).window(TumblingEventTimeWindows.of(Time.seconds(30)))
                .trigger(new TimeIntervalTrigger<>(5,TimeUnit.SECONDS))
                .process(new BaseStateProcessWindowFunction())
                .map(x -> {
                    System.out.println("key:" + x.page + ",window time:" + DateUtil.formatTimeStamp(x.windowTime,"yyyy-MM-dd HH:mm:ss") + ",uv:" + x.uv);
                    return null;
                });

        env.execute();
    }
}

文件:BaseStateProcessWindowFunction.class

public class BaseStateProcessWindowFunction extends ProcessWindowFunction<UserBehavior, PageUVResult, String, TimeWindow> {

    private static final StateTtlConfig stateTtlConfig = StateTtlConfig
            .newBuilder(Time.hours(3))
            .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
            .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
            .build();

    private transient ValueState<Long> uvState;

    private transient MapState<String,Boolean> userMapState;

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        ValueStateDescriptor<Long> uvStateDescriptor= new ValueStateDescriptor("value",Long.class);
        MapStateDescriptor<String, Boolean> userMapDescriptor = new MapStateDescriptor( "userIsExistMap", String.class, Boolean.class);
        uvStateDescriptor.enableTimeToLive(stateTtlConfig);
        userMapDescriptor.enableTimeToLive(stateTtlConfig);
        uvState = getRuntimeContext().getState(uvStateDescriptor);
        userMapState = getRuntimeContext().getMapState(userMapDescriptor);
    }

    @Override
    public void process(String page, Context context, Iterable<UserBehavior> iterable, Collector<PageUVResult> collector) throws Exception {
        if (uvState.value() == null) {
            uvState.update(0L);
        }
        long uv = uvState.value();
        for (UserBehavior userBehavior : iterable) {
            String userId = userBehavior.getUserId();
            if (!userMapState.contains(userId)) {
                userMapState.put(userId, true);
                uv++;
            }
        }
        uvState.update(uv);
        collector.collect(PageUVResult.of(page,context.window().getEnd(),uv));
    }
}
完整代码已上传至:https://github.com/xl-xueling/uvstatmultiplans.git
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值