flink入门- TumblingCountWindow和TumblingTimeWindow

概念

什么是 Window

在流处理应用中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理。当然我们可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处理,例如:在过去的1分钟内有多少用户点击了我们的网页。在这种情况下,我们必须定义一个窗口,用来收集最近一分钟内的数据,并对这个窗口内的数据进行计算。

Time Window

就如名字所说的,Time Window 是根据时间对数据流进行分组的。 Flink 提出了三种时间的概念,分别是event time(事件时间:事件发生时的时间),ingestion time(摄取时间:事件进入流处理系统的时间),processing time(处理时间:消息被计算处理的时间)

  • Tumbling Time Window

场景:统计10s内生成的数据之和,时间为event time

  1. 数据对象 Javabean
    @Data
    public class Element {
        public Integer value;
        public Long timestamp;
        
        public Element(){}
    
        public Element(Integer value, Long timestamp) {
            this.value = value;
            this.timestamp = timestamp;
        }
    
        @Override
        public String toString() {
            return "Element{" +
                    "value=" + value +
                    '}';
        }
    }

     

  2. 生成数据的工具类
    /**
     * 数据源--每秒生成一个对象Element(int number,long timestamp)
     */
    public class ElementGeneratorSource implements SourceFunction<Element> {
        final Logger logger = LoggerFactory.getLogger(ElementGeneratorSource.class);
        volatile boolean isRunning = true;
    
        @Override
        public void run(SourceContext<Element> ctx) throws Exception {
            int counter = 1;
    
            // flink程序启动20秒后
            long eventStartTime = System.currentTimeMillis() - 20000;
    
            // 使用上面的时间戳创建第一个事件
            Element element = new Element(counter++, eventStartTime);
            while (isRunning) {
                logger.info("Produced Element with value {} and timestamp {}", element.value, printTime(element.timestamp));
                ctx.collect(element);
    
                // 创建元素并分配具有随机性的时间戳,以便它们不与当前系统时钟时间相同
                element = new Element(counter++, element.timestamp + ThreadLocalRandom.current().nextLong(1000, 6000));
    
                Thread.sleep(1000);
            }
        }
    
        @Override
        public void cancel() {
            isRunning = false;
        }
    
        // 辅助函数以可读格式打印 epoch 时间
        String printTime(long longValue) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault()).toString();
        }
    
    }

     

  3.  main方法,用时间本身的时间戳分组,每10s一个窗口,计算数据
    final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
            env.setParallelism(1);
            // 设置为 EventTime,否则默认为 ProcessTime
            env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
            DataStreamSource<Element> elementStream = env.addSource(new ElementGeneratorSource());
            elementStream
                    // 在定义窗口之前,需要告诉Flink如何获取它接收到的每个元素的时间戳和水印
                    .assignTimestampsAndWatermarks(WatermarkStrategy.<Element>forBoundedOutOfOrderness(Duration.ofSeconds(3)).withTimestampAssigner((data, time) -> data.getTimestamp()))
                    .windowAll(TumblingEventTimeWindows.of(Time.seconds(10)))
                    .process(new ProcessAllWindowFunction<Element, Object, TimeWindow>() {
                        @Override
                        public void process(Context context, Iterable<Element> elements, Collector<Object> out) throws Exception {
                            TimeWindow window = context.window();
                            logger.info("窗口:【"+sdf.format(new Date(window.getStart()))+"-- "+sdf.format(new Date(window.getEnd()))+"】");
                            logger.info( "Computing sum for {}", elements );
                            int sum = 0;
                            for(Element e : elements) {
                                sum += e.value;
                            }
                            out.collect( sum );
    
                        }
                    })
                    .print();
    
            env.execute();

     

  4.  执行结果如下,计算窗口内的数据,每10s一个窗口

 

  • TumblingCountWindow

按照数量分组,如每5个对象 计算一下他们的和

 final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Element> elementStream = env.addSource(new ElementGeneratorSource());
        elementStream.countWindowAll(5)
                .aggregate(new AggregateFunction<Element, Long, Long>() {
                    @Override
                    public Long createAccumulator() {
                        return 0L;
                    }

                    @Override
                    public Long add(Element value, Long accumulator) {
                        return value.value + accumulator;
                    }

                    @Override
                    public Long getResult(Long accumulator) {
                        return accumulator;
                    }

                    @Override
                    public Long merge(Long a, Long b) {
                        return a + b;
                    }
                }).print();

        env.execute();

运行结果如下,达到5个数据后就开始计算

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值