我在GCS或其他受支持的文件系统上有一个目录,外部进程正在为其写入新文件。
我想写一个Apache Beam流式传输管道,它不断地在这个目录中查看新文件,并在每个新文件到达时读取和处理它们。这可能吗?
答案 0 :(得分:6)
这可以从Apache Beam 2.2.0开始。有几个API支持这个用例:
如果您使用的是TextIO
或AvroIO
,他们会通过TextIO.read().watchForNewFiles()
明确支持,readAll()
也是如此:
PCollection<String> lines = p.apply(TextIO.read()
.from("gs://path/to/files/*")
.watchForNewFiles(
// Check for new files every 30 seconds
Duration.standardSeconds(30),
// Never stop checking for new files
Watch.Growth.<String>never()));
如果您使用的是其他文件格式,则可以使用支持相同API的FileIO.match().continuously()
和FileIO.matchAll().continuously()
以及FileIO.readMatches()
。
API支持指定检查新文件的频率,以及何时停止检查(支持的条件是例如“如果在给定时间内没有出现新输出”,“观察N个输出后”,“自给定时间后开始检查“及其组合”。
请注意,此功能目前仅适用于Direct runner和Dataflow runner,仅适用于Java SDK。一般来说,它适用于任何支持 Splittable DoFn 的跑步者(参见capability matrix)。
答案 1 :(得分:1)
要增加Eugene的出色答案以及watchfornewfiles选项,还有其他几个选择;
根据您的延迟要求,可以使用多种选项来解决此要求。从SDK 2.9.0开始:
选项1:连续读取模式:
Java: FileIO,TextIO和其他几个IO源都支持连续读取新文件的源。
FileIO类支持连续监视单个文件模式的能力。 此示例每30秒重复匹配一个文件模式,连续地将新匹配的文件作为无限制的PCollection返回,并在1小时内没有新文件出现时停止显示。
PCollection<Metadata> matches = p.apply(FileIO.match()
.filepattern("...")
.continuously(
Duration.standardSeconds(30), afterTimeSinceNewOutput(Duration.standardHours(1))));
TextIO类支持使用watchForNewFiles属性流式传输新文件匹配。
PCollection<String> lines = p.apply(TextIO.read()
.from("/local/path/to/files/*")
.watchForNewFiles(
// Check for new files every minute
Duration.standardMinutes(1),
// Stop watching the filepattern if no new files appear within an hour
afterTimeSinceNewOutput(Duration.standardHours(1))));
请务必注意,文件列表不会在管道重新启动期间保留。为了应对这种情况,您可以通过流水线下游的进程或作为流水线本身的一部分来移动文件。另一个选择是将处理后的文件名存储在外部文件中,并在下一次转换时将列表重复数据删除。
Python: 从python的SDK 2.9.0开始,continuous选项不可用。
选项2:从外部来源触发流处理 您可以使Beam管道以流模式运行,该流具有无限制的源,例如PubSub。当新文件到达时,您可以使用Beam的外部过程检测文件到达,然后将具有URI作为有效载荷的PubSub消息发送到文件。然后,在带有PubSub源的DoFn中,可以使用该URI处理文件。
Java: 使用无限制的源IO(PubSubIO,KafakIO等)
Python: 使用不受限制的源IO(PubSubIO等)
选项3:从外部来源触发批处理模式处理 由于管道需要在处理开始之前启动,因此该方法引入了选项1和2的延迟。在这里,您可以从源文件系统中触发事件来计划或立即启动数据流过程。此选项最适合低频大文件大小更新。