为什么在 运行 管道时将零字节文件写入 GCS?

Why are zero byte files written to GCS when running a pipeline?

我们的 job/pipeline 正在将 ParDo 转换的结果写回 GCS,即使用 TextIO.Write.to("gs://...")

我们注意到当 job/pipeline 完成时,它会在输出桶中留下许多 0 字节文件。

管道的输入来自 GCS 的多个文件,所以我假设结果是分片的,这很好。

但是为什么我们得到的是空文件?

这些空分片很可能是中间管道步骤的结果,该步骤结果有些稀疏,一些预先分区的分片中没有记录。

例如如果在 TextIO.Write 之前有一个 GroupByKey,比如说,键空间被分片到范围 [00, 01), [01, 02), ..., [fe, ff)(总共 255 个分片),但是从这个 GroupByKey 的输入发出的所有实际键都在 [34, 81) 和 [a3, b5) 范围内,然后将生成 255 个输出文件,但其中大部分将变成空的。 (这是一个假设的分区方案,只是给你一个想法)

剩下的我会以问答的形式回答

为什么要生成空文件?如果没有任何输出,请不要创建文件! 确实,在技术上可以避免生产它们,例如通过在写入第一个元素时写入输出时延迟打开它们。 AFAIK 我们通常不这样做,因为空输出文件通常不是问题,而且空文件比没有文件更容易理解:如果只输出 50 个分片中的第一个,那将会非常混乱非空,你只会有一个名为 00001-of-000050 的输出文件:你想知道其他 49 个发生了什么。

但是为什么不增加一个post-删除空文件的处理步骤呢?原则上我们可以增加一个post-删除空文件的处理步骤如果空输出成为一个大问题,则空输出并重命名其余部分(以与 xxxxx-of-yyyyy 文件模式一致)。

空分片的存在是否表示我的管道出现问题? 许多空分片可能意味着系统选择的分片是 suboptimal/uneven,我们应该将计算分成更少、更统一的分片。如果这对您来说是个问题,您能否提供有关管道输出的更多详细信息,例如:您的屏幕截图显示非空输出也非常小:它们只包含少量记录吗? (如果是这样,在事先不知道数据的情况下,可能很难做到统一分片)

但是我的原始输入的分片不是空的,输出的分片不是输入的分片吗?如果你的管道有GroupByKey(或派生的)操作,会有是输入和输出中分片数量不同的中间步骤:例如一个操作可能消耗 30 个输入分片但产生 50 个输出分片,反之亦然。在不涉及GroupByKey的其他一些情况下,输入和输出中的不同数量的分片也是可能的。

TL;DR 如果您的整体输出是正确的,那不是错误,但请告诉我们这是否对您来说有问题:)