Flink中指定Key的几种方式

前言

在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];
            }
        });
### Flink 的状态存储机制及支持的方式 Flink 是一款强大的流处理框架,其状态管理功能对于高效执行复杂流处理任务至关重要。以下是关于 Flink 状态存储机制及其支持方式的详细介绍。 #### 1. 分布式状态存储 Flink 使用分布式存储系统来保存状态数据,从而确保高可用性和可扩展性[^2]。常见的分布式存储系统包括 HDFS 和 RocksDB。这些存储系统的引入使得即使在大规模集群环境下,Flink 也能有效应对海量状态数据的需求。 #### 2. 状态类型的支持 Flink 主要支持两种类型的状态:键控状态(Keyed State)和算子状态(Operator State)。 - **键控状态**:这种状态与特定 key 关联,在分区级别上独立存在。每个 key 对应一份独立的状态副本,适用于基于 key 进行分组的操作场景[^1]。 - **算子状态**:该状态属于整个算子实例,通常用于不依赖于 key 的全局操作,比如窗口聚合或连接器中的偏移量记录。 #### 3. 特殊状态——Broadcast State 除了上述基本状态外,Flink 还提供了 Broadcast State 来满足跨并行任务间的数据广播需求。Broadcast State 将一组数据发送到所有并行任务中,使它们能够访问相同的共享数据集[^4]。然而需要注意的是,由于需要在网络上传输大量数据,Broadcast State 可能会对性能造成一定影响,因此需谨慎设计使用场景。 #### 4. 状态持久化与可靠性保障 为了保证容错能力,Flink 实现了一套完整的检查点机制(Checkpointing),定期将当前运行时的状态写入可靠的分布式文件系统中作为备份。当发生故障时,可以从最近一次成功的 Checkpoint 中恢复作业继续执行。此外还有一种轻量级快照形式 Savepoints,允许手动触发以便迁移或者升级应用而无需中断服务。 #### 5. 状态缩减技术 随着长时间运行的应用程序不断积累新的输入事件,如果不加以控制,则可能导致内存占用过高甚至耗尽资源的情况出现。为此 Apache Flink 设计了几种有效的手段帮助开发者管理和压缩状态规模: - 利用时间窗函数限制保留周期内的历史信息; - 设置 TTL 参数让超过指定存活期限的部分被自动清除; - 应用增量更新模式仅保留最新变化部分而非全量复制; - 结合第三方数据库引擎如 RocksDB 提升效率同时节省空间开销等措施均有助于缓解这一问题带来的压力[^3]。 ```python # 示例代码展示如何定义带TTL配置的StateDescriptor from pyflink.datastream import StreamExecutionEnvironment from pyflink.table import EnvironmentSettings, TableEnvironment from pyflink.state import ValueStateDescriptor, TimeCharacteristic, StateTtlConfig env = StreamExecutionEnvironment.get_execution_environment() t_env = TableEnvironment.create(EnvironmentSettings.new_instance().in_streaming_mode().build()) ttl_config = StateTtlConfig \ .new_builder(Time.seconds(10)) \ .set_update_type(StateTtlConfig.UpdateType.OnCreateAndWrite) \ .disable_cleanup_in_background() \ .build() state_descriptor = ValueStateDescriptor("example_state", Types.STRING()) state_descriptor.enable_time_to_live(ttl_config) keyed_stream = env.from_collection([...]).key_by(lambda x: ...) value_state = keyed_stream.map(...).get_runtime_context().get_state(state_descriptor) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值