Flink 水位线、窗口、窗口分配器、窗口函数 四者简述 (附可运行代码)

目录

水位线

窗口

窗口分配器

滚动事件时间窗口

滑动事件时间窗口

会话事件时间窗口

窗口函数

代码实例

运行效果


水位线

水位线的主要内容就是一个时间戳,表示数据流中的时间

一个水位线t 表示在当前数据流中,事件时间已经达到了时间戳t,这代表t之前的所有数据都到齐了,之后出现的数据流中不会出现 t0

        Datastream.assignTimestampsAndWatermarks(
                WatermarkStrategy
                        .<Event>forBoundedOutOfOrderness(Duration.ZERO)     // 可容许的延迟时间 这里是0秒
                        .withTimestampAssigner((SerializableTimestampAssigner<T>) (x, l) -> x.time)     // 这里定义要抽取的时间 作为数据流中的事件
        );

窗口

我们知道在实时处理领域中数据是源源不断 没有边界的,我们把这称之为无界流的数据

而将flink中无界流的数据进行切分,切分为一个个有限数据的数据块,这就是所谓的窗口(windows)

窗口分配器

顾名思义,窗口分配器就是将数据划分到它应有的数据块(窗口)中,构建窗口函数前 我们都要先构建窗口分配器

滚动事件时间窗口

长度为5s的滚动窗口,每隔5s 对当前 5s 内的数据进行一次统计

// 调用window算子 传入窗口分配器的静态方法of 创建窗口分配器
Datastream.window(TumblingEventTimeWindows.of(Time.seconds(5)));

滑动事件时间窗口

长度为10s 滑动步长为5s的滑动窗口,5s统计一次,每次统计当前10s内的数据

Datastream.window(SlidingEventTimeWindows.of(Time.seconds(10),Time.seconds(5)));

会话事件时间窗口

一个会话超过10s内没有数据,就对他们进行合并

Datastream.window(EventTimeSessionWindows.withGap(Time.seconds(10)));

窗口函数

对窗口中的有界数据进行计算的操作 叫做窗口函数

如ReduceFunction、AggregateFunction、ProcessWindowFunction 等

代码实例

废话不多说 下面我们通过代码进行练习:

主程序

统计5s内各用户对网站的访问情况

package com.flink.wc.myflink.window;

import com.flink.wc.ClickSource;
import com.flink.wc.Event;
import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.datastream.WindowedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.EventTimeSessionWindows;
import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;

import java.time.Duration;

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


        DataStreamSource<Event> stream = env.addSource(new ClickSource());
        stream.print("stream");

        // 定义水位线
        // for Bounded Out Of Orderness 对于跳出秩序的边界
        SingleOutputStreamOperator<Event> stream02 = stream.assignTimestampsAndWatermarks(
                WatermarkStrategy
                        .<Event>forBoundedOutOfOrderness(Duration.ZERO)     // 可容许的延迟时间 这里是0秒
                        .withTimestampAssigner((SerializableTimestampAssigner<Event>) (event, l) -> event.time)     // 定义要抽取的时间 这里是event对象里面time属性
        );

        SingleOutputStreamOperator<Tuple2<String, Long>> stream03 =
                stream02.map(x -> Tuple2.of(x.user, 1L)).returns(Types.TUPLE(Types.STRING, Types.LONG));


        KeyedStream<Tuple2<String, Long>, String> stream04 =
                stream03.keyBy(x -> x.f0);

        // 窗口分配器
        // TumblingEventTimeWindows 方法是 滚动Tumbling 事件时间EventTime 窗口Windows
        WindowedStream<Tuple2<String, Long>, String, TimeWindow> windowedStream01 =
                stream04.window(TumblingEventTimeWindows.of(Time.seconds(5)));


        // SlidingEventTimeWindows 滑动 事件时间 窗口 长度为10s 滑动步长为5s————5s统计一次,每次统计10s内的数据
        WindowedStream<Tuple2<String, Long>, String, TimeWindow> windowedStream02 =
                stream04.window(SlidingEventTimeWindows.of(Time.seconds(10),Time.seconds(5)));

        // EventTimeSessionWindows 会话 事件时间 窗口 一个会话超过10s内没有数据,就对他们进行合并 这里的一个会话是指一个user属性???10s内没出现相同的user属性,就把他们合并然后进行聚合
        WindowedStream<Tuple2<String, Long>, String, TimeWindow> windowedStream03 =
                stream04.window(EventTimeSessionWindows.withGap(Time.seconds(10)));


        // 窗口函数  
        // 修改 windowedStream01 为 windowedStream02、 windowedStream03 观察不同窗口分配器的运行效果
        // 这个reduce(x, y)中 x是累加后的数据 y是下一个数据
        SingleOutputStreamOperator<Tuple2<String, Long>> resultStream =
                windowedStream01.reduce((x, y) -> Tuple2.of(x.f0, x.f1 + y.f1)).returns(Types.TUPLE(Types.STRING, Types.LONG));


        resultStream.print("stream06");


        try {
            env.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

Event类 用户访问网站的信息

user使用者、url用户访问的网址、time 用户的访问时间

作为数据流中的数据类型

package com.flink.wc;

public class Event {
    public String user;

    public String url;
    public long time;

    public Event() {
    }

    public Event(String user, String url, long time) {
        this.user = user;
        this.url = url;
        this.time = time;
    }

    @Override
    public String toString() {
        return "Event{" +
                "user='" + user + '\'' +
                ", url='" + url + '\'' +
                ", time=" + time +
                '}';
    }
}

自定义源算子

自动生成用户访问信息

package com.flink.wc;

import org.apache.flink.streaming.api.functions.source.SourceFunction;

import java.util.Calendar;
import java.util.Random;

public class ClickSource  implements SourceFunction<Event> {

    private Boolean running = true;

    @Override
    public void run(SourceContext<Event> ctx) throws Exception {
        Random random = new Random();
        String[] users = {"Mary","Alice","Bob","Cary"};
        String[] urls = {"./home", "./cart","./fav", "./prod?id=1","./prod?id=2"};

        while (running) {
            ctx.collect(new Event(
                users[random.nextInt(users.length)],
                urls[random.nextInt(urls.length)],
                Calendar.getInstance().getTimeInMillis()  //getTimeInMillis 方法返回当前时间    作为 event对象的time属性
            ));

            // 在这个循环中 每隔一秒 就collect(发送)一个数据
            Thread.sleep(1000);
        }
    }

    @Override
    public void cancel() {
        running = false;
    }
}

运行效果

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

电光火石尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值