Flink 滑动窗口详细解释及案例(非常全面,建议收藏慢慢看)

基于时间的滑动和滚动窗口 [重点]

滚动窗口- TumblingWindow概念

流是连续的,无界的(有明确的开始,无明确的结束

假设有个红绿灯,提出个问题:计算一下通过这个路口的汽车数量

对于这个问题,肯定是无法回答的,为何?

因为,统计是一种对固定数据进行计算的动作。

因为流的数据是源源不断的,无法满足固定数据的要求(因为不知道何时结束)

那么,我们换个问题:统计1分钟内通过的汽车数量

那么,对于这个问题,我们就可以解答了。因为这个问题确定了数据的边界,从无界的流数据中,取出了一部分有边界的数据子集合进行计算。

描述完整就是:每隔1分钟,统计这1分钟内通过汽车的数量。窗口长度是1分钟,时间间隔是1分钟,所以这样的窗口就是滚动窗口。

那么,这个行为或者说这个统计的数据边界,就称之为窗口。

同时,我们的问题,是以时间来划分被处理的数据边界的,那么按照时间划分边界的就称之为:时间窗口

反之,如果换个问题,统计100辆通过的车里面有多少宝马品牌,那么这个边界的划分就是按照数量的,这样的称之为:计数窗口

同时,这样的窗口被称之为滚动窗口,按照窗口划分依据分为:滚动时间窗口、滚动计数窗口。

滑动窗口– SlidingWindow概念

同样是需求,改为:

每隔1分钟,统计前面2分钟内通过的车辆数

对于这个需求我们可以看出,窗口长度是2分钟,每隔1分钟统计一次,窗口长度和时间间隔不相等,并且是大于关系,就是滑动窗口

或者:每通过100辆车,统计前面通过的50辆车的品牌占比

对于这个需求可以看出,窗口长度是50辆车,但是每隔100辆车统计一次

对于这样的窗口,我们称之为滑动窗口。

那么在这里面,统计多少数据是窗口长度(如统计2分钟内的数据,统计50辆车中的数据)

隔多久统计一次称之为滑动距离(如,每隔1分钟,每隔100辆车)

那么可以看出,滑动窗口,就是滑动距离不等于窗口长度的一种窗口

比如,每隔1分钟 统计先前5分钟的数据,窗口长度5分钟,滑动距离1分钟,不相等

比如,每隔100条数据,统计先前50条数据,窗口长度50条,滑动距离100条,不相等

那如果相等呢?相等就是比如:每隔1分钟统计前面1分钟的数据,窗口长度1分钟,滑动距离1分钟,相等。

对于这样的需求可以简化成:每隔1分钟统计一次数据,这就是前面说的滚动窗口

那么,我们可以看出:

滚动窗口:窗口长度= 滑动距离

滑动窗口:窗口长度!= 滑动距离

总结:其中可以发现,对于滑动窗口:

滑动距离> 窗口长度,会漏掉数据,比如:每隔5分钟,统计前面1分钟的数据(滑动距离5分钟,窗口长度1分钟,漏掉4分钟的数据)这样的东西,没人用。

滑动距离< 窗口长度,会重复处理数据,比如:每隔1分钟,统计前面5分钟的数据(滑动距离1分钟,窗口长度5分钟,重复处理4分钟的数据)

滑动距离= 窗口长度,不漏也不会重复,也就是滚动窗口

窗口的长度(大小) > 窗口的间隔 : 如每隔5s, 计算最近10s的数据 【滑动窗口】

窗口的长度(大小) = 窗口的间隔: 如每隔10s,计算最近10s的数据 【滚动窗口】

窗口的长度(大小) < 窗口的间隔: 每隔15s,计算最近10s的数据 【没有名字,不用】

案例演示

nc -lk 9999
有如下数据表示:
信号灯编号和通过该信号灯的车的数量
9,3
9,2
9,7
4,9
2,6
1,5
2,3
5,7
5,4
需求1:每5秒钟统计一次,最近5秒钟内,各个路口通过红绿灯汽车的数量--基于时间的滚动窗口
需求2:每5秒钟统计一次,最近10秒钟内,各个路口通过红绿灯汽车的数量--基于时间的滑动窗口 

没有添加窗口的写法:
package com.bigdata.day03.time;

import org.apache.flink.api.common.RuntimeExecutionMode;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

public class Demo07 {

    public static void main(String[] args) throws Exception {

        //1. env-准备环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);

        //2. source-加载数据
        DataStreamSource<String> streamSource = env.socketTextStream("localhost", 9999);

        // 9,2 --> (9,2)
        //3. transformation-数据处理转换
        streamSource.map(new MapFunction<String, Tuple2<Integer,Integer>>() {

            @Override
            public Tuple2<Integer, Integer> map(String line) throws Exception {
                String[] arr = line.split(",");
                int monitor_id = Integer.valueOf(arr[0]);
                int num = Integer.valueOf(arr[1]);
                return Tuple2.of(monitor_id,num);
            }
        }).keyBy(tuple->tuple.f0).sum(1).print();
        //4. sink-数据输出


        //5. execute-执行
        env.execute();
    }
}

此处的sum求和,中count ,其实是CartInfo中的一个字段而已。 

演示

 滚动演示

需求1:每5秒钟统计一次,最近5秒钟内,各个路口通过红绿灯汽车的数量--基于时间的滚动窗口

 

package com.bigdata.day03.time;

import org.apache.flink.api.common.RuntimeExecutionMode;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

public class Demo08 {

    public static void main(String[] args) throws Exception {

        //1. env-准备环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);

        //2. source-加载数据
        DataStreamSource<String> streamSource = env.socketTextStream("localhost", 9999);

        // 9,2 --> (9,2)
        //3. transformation-数据处理转换
        streamSource.map(new MapFunction<String, Tuple2<Integer,Integer>>() {

            @Override
            public Tuple2<Integer, Integer> map(String line) throws Exception {
                String[] arr = line.split(",");
                int monitor_id = Integer.valueOf(arr[0]);
                int num = Integer.valueOf(arr[1]);
                return Tuple2.of(monitor_id,num);
            }
        }).keyBy(tuple->tuple.f0)
                .window(TumblingProcessingTimeWindows.of(Time.minutes(1)))
                        .sum(1).print();
        //4. sink-数据输出


        //5. execute-执行
        env.execute();
    }
}

 以上代码的时间最好修改为1分钟,假如时间间隔是1分钟,那么48分03秒时输入的信号灯数据,49分整点会统计出来结果,原因是底层有一个算法。

滑动窗口的话,不太容易看到效果,因为有些数据被算到了多个窗口中,需要我们拿笔自己计算一下,对比一下:

接着进行滑动窗口的演示:

需求二:每5秒钟统计一次,最近5秒钟内,各个路口通过红绿灯汽车的数量

package com.bigdata.day03.time;

import org.apache.flink.api.common.RuntimeExecutionMode;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
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 Demo09 {

    public static void main(String[] args) throws Exception {

        //1. env-准备环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);

        //2. source-加载数据
        DataStreamSource<String> streamSource = env.socketTextStream("localhost", 9999);

        // 9,2 --> (9,2)
        //3. transformation-数据处理转换
        streamSource.map(new MapFunction<String, Tuple2<Integer,Integer>>() {

            @Override
            public Tuple2<Integer, Integer> map(String line) throws Exception {
                String[] arr = line.split(",");
                int monitor_id = Integer.valueOf(arr[0]);
                int num = Integer.valueOf(arr[1]);
                return Tuple2.of(monitor_id,num);
            }
        }).keyBy(tuple->tuple.f0)
                .window(SlidingProcessingTimeWindows.of(Time.seconds(10),Time.seconds(5)))
                        .sum(1).print();
        //4. sink-数据输出


        //5. execute-执行
        env.execute();
    }
}

在spark中:

打印rdd 用什么 ? foreach(lambda x: print(x))

打印dataFrame: show()

在flink中:打印dataStream 使用 print()

 

<think>好的,用户想知道如何在VSCode中使用多光标操作。首先,我得回忆一下自己使用VSCode的经验,以及相关的文档资料。记得之前看过一些教程提到过多种多光标的方法,比如Alt+Click或者使用快捷键添加光标。可能需要分步骤解释不同的方法,确保用户能理解。 首先,用户可能对多光标操作不太熟悉,所以需要从基础开始。例如,按住Alt键点击不同位置添加多个光标,或者用Ctrl+D选择相同词。然后,可能需要提到列选择模式,也就是按住Shift+Alt拖动鼠标,这在处理表格或对齐代码时很有用。 还要考虑不同的操作系统,比如Mac上的快捷键可能不同,比如Cmd代替Ctrl。这点需要特别说明,避免用户混淆。另外,一些高级技巧,比如使用Ctrl+Shift+L同时选择所有匹配项,或者Ctrl+F2修改所有匹配的变量名,这些对提高效率很有帮助。 然后要检查引用来源是否正确。根据用户提供的引用,引用[1]提到多光标工作流程,引用[3]也涉及光标移动的技巧。需要确保回答中的技巧都能对应到正确的引用,避免错误。 还要注意用户提到的LaTeX格式要求,虽然当前问题不涉及数学公式,但回答中的代码块和步骤需要正确格式化。例如,代码示例要用反引号包裹,并标明语言。同时,确保回答结构清晰,分点列出,方便用户逐步学习。 可能用户是开发者或经常需要编辑代码的人,他们需要高效编辑代码的方法。所以除了基本操作,还可以推荐一些扩展或设置,比如Emmet缩写或自定义快捷键,提升他们的工作效率。 最后,生成的相关问题要围绕多光标操作展开,比如如何自定义快捷键,如何结合扩展使用,或者处理大文件的技巧。这些问题应该能帮助用户进一步探索VSCode的高级功能。 总结一下,回答需要涵盖基本的多光标操作方法、快捷键、列选择、高级技巧,并引用正确的资料。同时用中文清晰解释,结构分明,确保用户能轻松跟随步骤操作。</think>### VSCode多光标操作指南 多光标操作是提升代码编辑效率的核心技巧,以下是具体实现方式: 1. **基础多光标创建** - **鼠标点击**:按住$Alt$键(Mac为$Option$)点击不同位置,可创建多个独立光标[^1] - **快捷键添加**:$Ctrl+Alt+↑/↓$(Windows)或$Cmd+Option+↑/↓$(Mac)在相邻行创建垂直光标 2. **批量选择相同内容** ```python # 示例:同时修改多个变量名 def calculate(a, b): result = a + b # 选中所有a变量 return result * a ``` - 选中单词后按$Ctrl+D$逐个选中相同内容 - $Ctrl+Shift+L$直接选中全部匹配项[^3] 3. **列选择模式** - 按住$Shift+Alt$拖动鼠标实现块状选择 - 特别适用于修改CSV数据或对齐代码 4. **高级应用技巧** - 使用$Ctrl+F2$修改所有匹配标识符 - 配合Emmet缩写实现批量HTML标签生成 - 通过正则查找替换配合多光标操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值