Flink中指定Key的几种方式

在Flink中,某些算子要求在数据元上定义key,部分操作需根据key分组。Flink数据模型非键值对格式,key可人为指定。本文介绍了三种指定key的方式,包括使用Tuples、Field Expression和Key Selector Functions,并说明了各自的使用方法和注意事项。
前言

在Flink中比如某些算子(join,coGroup,keyBy,groupBy)要求在数据元上定义key。另外有些算子操作,例如reduce,groupReduce,Aggregate,Windows需要数据在处理之前根据key进行分组。

在Flink中数据模型不是基于Key,Value格式处理的,因此不需将数据处理成键值对的格式,key是“虚拟的”,可以人为的来指定,实际数据处理过程中根据指定的key来对数据进行分组,DataSet中使用groupBy来指定key,DataStream中使用keyBy来指定key。那么如何指定keys呢?

一.使用Tuples来指定key

定义元组来指定key可以指定tuple中的第几个元素当做key,或者指定tuple中的联合元素当做key。需要使用org.apache.flink.api.java.tuple.TupleXX包下的tuple,最多支持25个元素且Tuple必须new创建。

如果Tuple是嵌套的格式,例如:DataStream<Tuple3<Tuple2<Integer, Float>,String,Long>> ds,如果指定keyBy(0)则会使用内部的整个Tuple2作为key。如果想要使用内部Tuple2中的Float格式当做key,可以使用keyBy("f0.f1")这样的形式指定。

这里需要注意,在Flink的Tuple中指定的key的下标从0开始算起,这里不像Scala中的Tuple从1开始算起,同时一般需要指定key的函数中都可以有两种写法,一种是直接写数字0,1,2等等,还有一种是写字符串的形式前面的0,1,2对应的字符串的表达形式为f1,f2,f3。

如果需要指定多个字段当做联合的Key,可以写成keyBy(0,1),如果写成字符串形式在字符串中指定多个key,还可以写成keyBy("f0","f1")的形式。

二.使用Field Expression来指定key

可以使用Field Expression来指定key,一般作用的对象可以是类对象,或者嵌套的Tuple格式的数据。

对于这种形式的使用,注意点如下:

1.对于类对象可以使用类中的字段来指定key,类对象定义需要注意:

  • 类的访问级别必须是public
  • 必须写出默认的空的构造函数
  • 类中所有的字段必须是public的或者必须有getter,setter方法。
  • Flink必须支持字段的类型。

2.对于嵌套的Tuple类型的Tuple数据可以使用"xx.f0"表示嵌套tuple中第一个元素,也可以直接使用”xx.0”来表示第一个元素。

三.使用Key Selector Functions来指定key

使用key Selector这种方式选择key,非常方便,可以从数据类型中指定想要的key.

KeyedStream<String, String> keyBy = socketText.keyBy(new KeySelector<String, String>() {
            @Override
            public String getKey(String line) throws Exception {
                return line.split("\t")[2];
            }
        });
Apache Flink 提供了多种窗口类型,以满足不同的流处理需求。这些窗口类型主要包括: ### 滚动窗口(Tumbling Windows) 滚动窗口是一种固定大小、非重叠的窗口。每个数据元素只能属于一个窗口,并且窗口之间首尾相接,没有重叠。例如,一个5秒的滚动窗口会将每5秒的数据分组一次,确保每个时间点只属于一个窗口[^1]。 ```java // 示例:使用滚动窗口进行每5秒的数据聚合 DataStream<Tuple2<String, Integer>> input = ...; input.keyBy(keySelector) .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) { return new Tuple2<>(value1.f0, value1.f1 + value2.f1); } }); ``` ### 滑动窗口(Sliding Windows) 滑动窗口同样是固定大小的窗口,但窗口之间可以部分重叠。这种窗口类型允许数据在多个窗口中被处理,从而提供更细粒度的结果更新。例如,一个10秒的滑动窗口,每5秒滑动一次,会每隔5秒生成一个新的结果,包含最近10秒的数据[^3]。 ```java // 示例:使用滑动窗口进行每10秒的数据处理,每5秒滑动一次 DataStream<Tuple2<String, Integer>> input = ...; input.keyBy(keySelector) .window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5))) .reduce(new ReduceFunction<Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) { return new Tuple2<>(value1.f0, value1.f1 + value2.f1); } }); ``` ### 会话窗口(Session Windows) 会话窗口用于将数据流中的事件分组为不连续的“会话”,这些会话由活跃期和非活跃期定义。当两个事件之间的间隔超过指定的超时时间,则认为它们属于不同的会话。会话窗口适用于分析用户行为模式,如网页点击流分析[^4]。 ```java // 示例:使用会话窗口来处理用户点击流数据 DataStream<Tuple2<String, Integer>> input = ...; input.keyBy(keySelector) .window(ProcessingTimeSessionWindows.withGap(Time.minutes(1))) .reduce(new ReduceFunction<Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) { return new Tuple2<>(value1.f0, value1.f1 + value2.f1); } }); ``` ### 全局窗口(Global Windows) 全局窗口将所有数据分配到同一个窗口中,通常与自定义的触发器结合使用。它适用于需要对整个数据流进行聚合操作的场景,但由于其无界的特性,必须谨慎使用以避免内存溢出[^1]。 ```java // 示例:使用全局窗口进行全量数据聚合 DataStream<Tuple2<String, Integer>> input = ...; input.keyBy(keySelector) .window(GlobalWindows.create()) .trigger(new MyCustomTrigger<>()) .reduce(new ReduceFunction<Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) { return new Tuple2<>(value1.f0, value1.f1 + value2.f1); } }); ``` ### 时间窗口(Time Windows)与计数窗口(Count Windows) 除了上述窗口类型外,Flink 还提供了基于时间和计数的窗口实现。时间窗口根据处理时间或事件时间划分数据,而计数窗口则根据元素数量划分窗口。例如,计数窗口可以在达到一定数量的元素后触发计算,适用于需要按批次处理数据的场景。 ```java // 示例:使用计数窗口,每100个元素触发一次计算 DataStream<Tuple2<String, Integer>> input = ...; input.keyBy(keySelector) .countWindow(100) .reduce(new ReduceFunction<Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) { return new Tuple2<>(value1.f0, value1.f1 + value2.f1); } }); ``` 通过灵活选择和组合这些窗口类型,开发者可以高效地处理各种复杂的流式数据场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值