Flink学习8-时间语义及Window

三种时间类型

EventTime -> 事件时间 指的是数据本身携带的时间。这个时间是在事件产生时的时间
执行结果确定,能够处理乱序数据和延迟数据

ProcTime-> 处理时间 进行Flink运算的时间
数据处理性能好,延迟低,但处理的数据有不确定性,可能是乱序。

IngestionTime -> 摄入时间 指的是数据进入 Flink 的时间;在系统内部,会把它当做事件时间来处理
这个一般不做讨论,主要使用上面两种类型

Window -> 将无界流拆分成有界流

window分类

1、按照是否为keyed stream来划分,keyed stream用window()方法,no-keyed stream用windowAll()方法。一般来说做了keyby操作后数据流就变为keyed stream了。
2、按照时间划分,Time-based Window,他是一个左闭右开的区间,[start_time,end_time)
3、按照窗口里元素个数划分,Count-based Window,他和时间无关。
4、按照窗口分配器分类,WindowAssigner。一个窗口分配器可以将一个元素分配到一个或者多个窗口里面来。具体可以划分为:滚动窗口(tumbling window)、滑动窗口(sliding window)、会话窗口(session window)、全局窗口(global window)及自定义窗口。

滚动窗口

在这里插入图片描述
滚动窗口需要指定一个窗口大小window size,window size可以按照时间来指定(EventTime&ProcTime),也可以按照元素数量来指定。一个元素只会被划分到一个窗口里面,窗口里元素不会重叠。
在这里插入图片描述

滑动窗口

在这里插入图片描述
滑动窗口需要指定一个窗口大小window size和滑动步长 window slide。一个元素可能会被划分到多个窗口里面,窗口里元素会有重叠。
在这里插入图片描述

会话窗口

在这里插入图片描述
会话窗口指定一个gap,当这个session gap内没有新元素传进来的时候就结束当前会话。这个 session gap可以是一段时间,也可以是动态的一个元素。在这里插入图片描述

窗口函数

按照计算方式分为两类:增量计算(ReduceFunction, AggregateFunction),来一条处理一条。全量计算(ProcessWindowFunction)数据先缓存buffer里,窗口结束再进行计算。前者计算效率更高。
以下是窗口分配器结合三种窗口函数的使用案例:

import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStreamSink;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.ProcessingTimeSessionWindows;
import org.apache.flink.streaming.api.windowing.assigners.SlidingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

public class WindowApp {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        test07(env);
        env.execute();
    }

    /**
     * 不带keybey的流用windowall
     */
    public static void test01(StreamExecutionEnvironment env){
        env.socketTextStream("localhost",9633)
                .map(new MapFunction<String, Integer>() {
                    @Override
                    public Integer map(String s) throws Exception {
                        return Integer.parseInt(s);
                    }
                })
                .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .sum(0)
                .print();
    }

    /**
     * 带keybey的流用window
     */
    public static void test02(StreamExecutionEnvironment env){
        env.socketTextStream("localhost",9633)
                .map(new MapFunction<String, Tuple2<String,Integer>>() {
                    @Override
                    public Tuple2<String, Integer> map(String s) throws Exception {
                        return Tuple2.of(s,1);
                    }
                })
                .keyBy(x -> x.f0)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .sum(1)
                .print();
    }

    /**
     * 基于ReduceFunction的滚动窗口计算
     * windowfunction增量处理方式:来一条处理一条
     */
    public static void test03(StreamExecutionEnvironment env){
        env.socketTextStream("localhost",9633)
                .map(new MapFunction<String, Tuple2<String,Integer>>() {
                    @Override
                    public Tuple2<String, Integer> map(String s) throws Exception {
                        return Tuple2.of(s,1);
                    }
                })
                .keyBy(x -> x.f0)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .reduce(new ReduceFunction<Tuple2<String, Integer>>() { /** 实现增量计算**/
                @Override
                public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) throws Exception {
                    return Tuple2.of(value1.f0,value1.f1+value2.f1);
                }
                })
                .print();
    }

    /**
     * processFunction全量缓存
     */
    public static void test04(StreamExecutionEnvironment env) {
        env.socketTextStream("localhost",9633)
                .map(new MapFunction<String, Tuple2<String,Integer>>() {
                    @Override
                    public Tuple2<String, Integer> map(String s) throws Exception {
                        return Tuple2.of("sf",Integer.parseInt(s));
                    }
                })
                .keyBy(x -> x.f0)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .process(new ProcessFun())
                .print();
    }

    /**
     * 基于processTime的会话窗口
     */
    public static void test05(StreamExecutionEnvironment env) {
        env.socketTextStream("localhost",9633)
                .map(new MapFunction<String, Integer>() {
                    @Override
                    public Integer map(String s) throws Exception {
                        return Integer.parseInt(s);
                    }
                })
                .windowAll(ProcessingTimeSessionWindows.withGap(Time.seconds(5)))
                .sum(0)
                .print();
    }

    /**
     * 基于ProcessingTime的Non-Keyed和Keyed的滑动窗口
     */
    public static void test06(StreamExecutionEnvironment env) {
        DataStreamSink<Integer> nokeyedstream = env.socketTextStream("localhost", 9633)
                .map(new MapFunction<String, Integer>() {
                    @Override
                    public Integer map(String s) throws Exception {
                        return Integer.parseInt(s);
                    }
                })
                .windowAll(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
                .sum(0)
                .print();


        DataStreamSink<Tuple2<String, Integer>> keyedstream = env.socketTextStream("localhost", 9633)
                .map(new MapFunction<String, Tuple2<String, Integer>>() {
                    @Override
                    public Tuple2<String, Integer> map(String s) throws Exception {
                        return Tuple2.of(s, 1);
                    }
                })
                .keyBy(x -> x.f0)
                .window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
                .sum(1)
                .print();
    }

    /**
     * 基于AggregateFunction的滚动窗口
     */
    public static void test07(StreamExecutionEnvironment env){
        env.socketTextStream("localhost",9633)
                .map(new MapFunction<String, Tuple2<String,Long>>() {
                    @Override
                    public Tuple2<String, Long> map(String s) throws Exception {
                        String[] splits = s.split(",");
                        return Tuple2.of(splits[0],Long.parseLong(splits[1]));
                    }
                })
                .keyBy(x -> x.f0)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .aggregate(new AverageAggregate())
                .print();
    }
}
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;

/**
 * IN:待处理DataStream中每个元素的类型
 * OUT:结果DataStream中每个元素的类型
 * KEY:keyBy中指定key的类型
 * W extends Window: TimeWindow
 */
public class ProcessFun extends ProcessWindowFunction<Tuple2<String,Integer>,String,String, TimeWindow> {
    @Override
    public void process(String s, Context context, Iterable<Tuple2<String, Integer>> iterable, Collector<String> collector) throws Exception {
        System.out.println("----process invoked...----");
        int maxValue = Integer.MIN_VALUE;
        for (Tuple2<String, Integer> elements : iterable) {
            maxValue = Math.max(elements.f1,maxValue);
        }
        collector.collect("当前窗口的最大值是:"+maxValue);
    }
}
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.api.java.tuple.Tuple2;

/**
 *
 <IN> – 输入值
 <ACC> – 中间聚合的值
 <OUT> – 输出结果的值
 */
public class AverageAggregate implements AggregateFunction<Tuple2<String, Long>, Tuple2<Long, Long>, Double> {
    @Override
    public Tuple2<Long, Long> createAccumulator() { //创建一个累加器,并初始化累加器的值
        return new Tuple2<>(0L, 0L);
    }


    @Override
    public Tuple2<Long, Long> add(Tuple2<String, Long> value, Tuple2<Long, Long> accumulator) {
        //System.out.println("累加器的值和传入初始值进行累加:"+accumulator.f0 + value.f1+"累加器初始值加一:"+accumulator.f1 + 1L);
        return new Tuple2<>(accumulator.f0 + value.f1, accumulator.f1 + 1L);//累加器的值和传入初始值进行累加,累加器初始值加一
    }

    @Override
    public Double getResult(Tuple2<Long, Long> accumulator) {
        //System.out.println("分子:"+accumulator.f0+"分母:"+accumulator.f1);
        return ((double) accumulator.f0) / accumulator.f1;
    }

    @Override
    public Tuple2<Long, Long> merge(Tuple2<Long, Long> a, Tuple2<Long, Long> b) {
        return new Tuple2<>(a.f0 + b.f0, a.f1 + b.f1);//相同key的数据进行合并
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值