Apache flink 弗林克:如何存储状态并在另一个流中使用?

Apache flink 弗林克:如何存储状态并在另一个流中使用?,apache-flink,flink-streaming,Apache Flink,Flink Streaming,我有一个Flink的用例,我需要从文件中读取信息,存储每一行,然后使用这个状态过滤另一个流 我现在使用connect操作符和RichCoFlatMapFunction完成了所有这些工作,但感觉太复杂了。此外,我担心flatmap 2可能在从文件加载所有状态之前开始执行: fileStream .connect(partRecordStream.keyBy((KeySelector<PartRecord, String>) partRecord -> partRecord

我有一个Flink的用例,我需要从文件中读取信息,存储每一行,然后使用这个状态过滤另一个流

我现在使用
connect
操作符和
RichCoFlatMapFunction
完成了所有这些工作,但感觉太复杂了。此外,我担心
flatmap 2
可能在从文件加载所有状态之前开始执行:

fileStream
    .connect(partRecordStream.keyBy((KeySelector<PartRecord, String>) partRecord -> partRecord.getPartId()))
    .keyBy((KeySelector<String, String>) partId -> partId, (KeySelector<PartRecord, String>) partRecord -> partRecord.getPartId())
    .flatMap(new RichCoFlatMapFunction<String, PartRecord, PartRecord>() {
        private transient ValueState<String> storedPartId;
        @Override
        public void flatMap1(String partId, Collector<PartRecord> out) throws Exception {
            // store state
            storedPartId.update(partId);
        }

        @Override
        public void flatMap2(PartRecord record, Collector<PartRecord> out) throws Exception {
            if (record.getPartId().equals(storedPartId.value())) {
                out.collect(record);
            } else {
                // do nothing
            }
        }

        @Override
        public void open(Configuration parameters) throws Exception {
            ValueStateDescriptor<String> descriptor =
                    new ValueStateDescriptor<>(
                            "partId", // the state name
                            TypeInformation.of(new TypeHint<String>() {}),
                            null);
            storedPartId = getRuntimeContext().getState(descriptor);
        }
    });
fileStream
.connect(partRecordStream.keyBy((KeySelector)partRecord->partRecord.getPartId())
.keyBy((KeySelector)partId->partId,(KeySelector)partRecord->partRecord.getPartId())
.flatMap(新的RichCoFlatMapFunction(){
私有瞬态值状态存储部分;
@凌驾
public void flatMap1(字符串partId,收集器out)引发异常{
//存储状态
存储的partId.update(partId);
}
@凌驾
公共void flatMap2(PartRecord记录,收集器输出)引发异常{
if(record.getPartId().equals(storedPartId.value())){
取出、收集(记录);
}否则{
//无所事事
}
}
@凌驾
公共void open(配置参数)引发异常{
ValueStateDescriptor描述符=
新的ValueStateDescriptor(
“partId”,//状态名称
TypeInformation.of(新的TypeHint(){}),
无效);
storedPartId=getRuntimeContext().getState(描述符);
}
});

是否有更好的方法(从Flink 1.1.3开始)来完成这种加载状态模式,然后在后续流中使用它?

您对
CoFlatMapFunction
的担忧是正确的。调用
flatmap 1
flatmap 2
的顺序无法控制,并且取决于数据到达的顺序。因此,
flatmap 1
读取所有数据之前,可能会调用
flatmap 2

在Flink 1.1.3中,在开始处理流之前读取所有数据的唯一方法是使用
RichFlatMapFunction
open()
方法中的数据,即,您必须手动读取和解析文件


这基本上是一种广播连接策略,即,操作符的每个并行实例都将执行此操作。缺点是文件的数据将被复制。这样做的好处是,您不必洗牌“主”流(无需使用
keyBy()
)。

啊,我明白了。因此,我可以在
open()
方法中解析文件,但只要我不使用
keyBy()
上游,就只有一个操作符实例。但是,这实际上是一个串行操作,对吗?
FlatMap
操作符也可以并行运行,而无需调用
keyBy()
。您只需指定运算符的并行性。但是,数据将随机分布在并行线程中
keyBy
将对数据进行哈希分区。如果有多个
FlatMap
操作符,则每个操作符都会读取文件并保存状态。因此,您有冗余的IO和内存使用,但操作员将并行运行。@FabianHueske按照这种方法,每次更新文件时,都需要重新启动作业以获取更新的内容。在flink中是否有一种方法,在文件状态可用之前不处理主流记录。基本上我们可以设置元素的处理顺序。