Apache flink RichCoFlatMapFunction中的MapState始终为空

Apache flink RichCoFlatMapFunction中的MapState始终为空,apache-flink,flink-streaming,flink-statefun,Apache Flink,Flink Streaming,Flink Statefun,我在读两条溪流。一个有记录,一个有元数据 这是我第一次希望我的应用程序通过扫描整个表并将其保存到Flink的MapState来构建元数据。表上的更新将通过元数据流捕获,MapState将相应地更新 从第二次开始,我想使用MapState,而不是读取整个表 下面是我对这个功能的实现,但是我的MapState总是空的,我在这里做错了什么吗 public class CustomCoFlatMap extends RichCoFlatMapFunction<Record, Metadata, O

我在读两条溪流。一个有记录,一个有元数据

这是我第一次希望我的应用程序通过扫描整个表并将其保存到Flink的MapState来构建元数据。表上的更新将通过元数据流捕获,MapState将相应地更新

从第二次开始,我想使用MapState,而不是读取整个表

下面是我对这个功能的实现,但是我的MapState总是空的,我在这里做错了什么吗

public class CustomCoFlatMap extends RichCoFlatMapFunction<Record, Metadata, Output> {

    private transient DataSource datasource;
    private transient MapState<String, Metadata> metadataState;

    @Inject
    public void setDataSource(DataSource datasource) {
        this.datasource = datasource;
    }

    @Override
    public void open(Configuration parameters) throws Exception {
        final RichFunctionComponent component = DaggerRichFunctionComponent.builder()
                .richFunctionModule(RichFunctionModule.builder()
                        .runtimeContext(getRuntimeContext())
                        .build())
                .build();
        component.inject(this);

        // read MapState from snapshot
        metadataState = getRuntimeContext().getMapState(new MapStateDescriptor<String, Cluster>("metadataState",
                TypeInformation.of(new TypeHint<String>(){}), TypeInformation.of(new TypeHint<Metadata>() {})));
    }

    @Override
    public void flatMap2(Metadata metadata, Collector<Output> collector) throws Exception {
        // this should happen only when application starts for first time
        // from next time, application will read from snapshot
        readMetadataForFirstTime();

        // update metadata in MapState
        this.metadataState.put(metadata.getId(), metadata);
    }

    @Override
    public void flatMap1(Record record, Collector<Output> collector) throws Exception {
        
        readMetadataForFirstTime();
        
        Metadata metadata = this.metadataState.get(record.getId());

        Output output = new Output(record.getId(), metadataState.getName(), metadataState.getVersion(), metadata.getType());
    
        collector.collect(output);
    }

    private void readMetadataForFirstTime() throws Exception {
        if(this.metadataState.iterator().hasNext()) {
            // metadataState from snapshot has data
            // not reading from table
            return;
        }

        // do this only once
        // read metadata from table and add it to MapState
        List<Metadata> metadataList = datasource.listAllMetadata();
        for(Metadata metadata: metadataList) {
            this.metadataState.put(metadata.getid(), metadata);
        }

    }
}
公共类CustomCoFlatMap扩展了RichCoFlatMapFunction{
私有瞬态数据源;
私有瞬态映射状态元数据状态;
@注入
public void setDataSource(数据源数据源){
this.datasource=数据源;
}
@凌驾
公共void open(配置参数)引发异常{
final RichFunctionComponent组件=DaggerRichFunctionComponent.builder()
.richFunctionModule(richFunctionModule.builder())
.runtimeContext(getRuntimeContext())
.build())
.build();
组件。注入(此);
//从快照读取映射状态
metadataState=getRuntimeContext().getMapState(新的MapStateDescriptor(“metadataState”),
of(new TypeHint(){}),TypeInformation.of(new TypeHint(){}));
}
@凌驾
公共void flatMap2(元数据、收集器)引发异常{
//只有当应用程序第一次启动时,才会发生这种情况
//从下一次开始,应用程序将从快照读取数据
readMetadataForFirstTime();
//在MapState中更新元数据
this.metadataState.put(metadata.getId(),metadata);
}
@凌驾
公共void flatMap1(记录记录、收集器)引发异常{
readMetadataForFirstTime();
Metadata Metadata=this.metadataState.get(record.getId());
输出输出=新输出(record.getId()、metadataState.getName()、metadataState.getVersion()、metadata.getType());
collect.collect(输出);
}
私有void readMetadataForFirstTime()引发异常{
if(this.metadataState.iterator().hasNext()){
//快照中的metadataState包含数据
//不在桌子上看书
返回;
}
//只做一次
//从表中读取元数据并将其添加到MapState
List metadataList=datasource.listAllMetadata();
for(元数据:metadataList){
this.metadataState.put(metadata.getid(),metadata);
}
}
}
编辑:应用程序的其余部分

DataStream<Metadata> metadataKeyedStream =
                env.addSource(metadataStream)
                        .keyBy(Metadata::getId);

SingleOutputStreamOperator<Output> outputStream =
                env.addSource(recordStream)
                        .assignTimestampsAndWatermarks(new RecordTimeExtractor())
                        .keyBy(Record::getId)
                        .connect(metadataKeyedStream)
                        .flatMap(new CustomCoFlatMap());
数据流metadataKeyedStream= 环境addSource(元数据流) .keyBy(元数据::getId); SingleOutputStream运算符outputStream= 环境添加源(记录流) .assignTimestampsAndWatermarks(新的RecordTimeExtractor()) .keyBy(记录::getId) .connect(metadataKeyedStream) .flatMap(新的CustomCoFlatMap());
MapState
是一种密钥分区状态——这意味着Flink为输入流中的每个不同密钥维护一个单独的
Map
readMetadataForFirstTime
必须读取并插入由
RichCoFlatMapFunction
处理的流中每个键的数据,因为每个键都有一个单独的映射

您可能希望以不同的方式处理此问题,具体取决于您正试图做什么。 例如,如果您只想为源流中的每个键存储一个值,那么应该使用
ValueState
,而不是
MapState
。您可以将
ValueState
视为切分键/值存储,其中有状态运算符的每个并行实例(例如
RichCoFlatMapFunction
)将具有键空间片段的值
MapState
适用于需要为每个键存储整个hashmap而不是单个对象的情况


(如果我错误判断了问题所在,请分享更多上下文,说明应用程序的其余部分是如何使用此
RichCoFlatMapFunction

使用
ValueState
而不是
MapState
是有意义的,因为我每个键只有一个值。但是如何将
元数据
写入每个Id的值状态?我是否应该使用
ValueStateDescriptor
名称作为
Id
和值作为
Metadata
保存?如果是,那么我应该执行
getRuntimeContext().getState(新的ValueStateDescriptor(metadata.getId(),TypeInformation.of(new-TypeHint(){}))
对于在
flatmap 1
flatmap 2
中收到的每个记录,我建议您查看和中的Flink培训资料,其中详细解释了如何工作,并包括一些示例。状态描述符名称应为常量字符串;像“元数据”这样的东西就可以了。如果元数据是一个POJO,那么您可以简单地执行类似于
新的ValueStateDescriptor(“Metadata”,Metadata.class)
的操作。明白了,我想知道如何将所有
元数据
放入
ValueState
中,也就是说,当我第一次调用
readMetadataForFirstTime()
,我想将
元数据的列表添加到
ValueState
中。但我只看到
ValueState
上的更新,如何将所有
Metadata
列表添加到`ValueState`中?换句话说,我希望读取表
Metadata
中的所有条目,并仅在应用程序第一次启动时将它们保存到state。当应用程序重新启动时,我希望从状态中检索它们,而不是再次读取表。