Google cloud dataflow 限制梁管道AvroIO.write()中每个碎片的记录数

Google cloud dataflow 限制梁管道AvroIO.write()中每个碎片的记录数,google-cloud-dataflow,apache-beam,avro,Google Cloud Dataflow,Apache Beam,Avro,正在尝试使用AvroIO写入两组文件 我有一个PCollection,我想在不同的文件集中写入Item1和Item2 我想以一种方式分割碎片,使得fileItem1 XX of NN应该包含fileItem2 XX of NN中的相应值 我们对每个分片文件中的元素数量有一个限制(比如单个文件中有20000个项目)没有直接的选项来限制每个分片的记录数量,但是通过将分片数量设置为1,然后限制每个文件的记录数量,可以实现类似的结果 一个选项是在DoFn中使用FinishBundle来限制元素的数量,然

正在尝试使用AvroIO写入两组文件

我有一个PCollection,我想在不同的文件集中写入Item1和Item2

我想以一种方式分割碎片,使得fileItem1 XX of NN应该包含fileItem2 XX of NN中的相应值


我们对每个分片文件中的元素数量有一个限制(比如单个文件中有20000个项目)

没有直接的选项来限制每个分片的记录数量,但是通过将分片数量设置为1,然后限制每个文件的记录数量,可以实现类似的结果

一个选项是在
DoFn
中使用
FinishBundle
来限制元素的数量,然后编写它们,您可以看到Python的一个示例

此外,我认为通过创建最大数量记录的批处理,然后使用这些结果编写文件,可以实现类似的行为

请注意,这两种方法都可能会影响管道的性能,因为跟踪记录数的需要会限制并行性

这里有一段代码,可以作为参考。我使用并修改了它来编写Avro文件。该示例为您提供了一个包含已计数单词的
KV
,因此我使用它时,就好像它与您的
KV
相似一样

static void runWordCount(WordCountOptions){
Pipeline p=Pipeline.create(选项);
//读取文件
p、 apply(“ReadLines”,TextIO.read().from(options.getInputFile()))
.apply(new CountWords())//原始数据-KV
.apply(使用“1”的键)//添加人工键-KV
.apply(GroupIntoBatches.ofSize(1000))//每个碎片最大记录大小的组->KV
.apply(ParDo.of(new SplitForFiles())//拆分为写入文件-KV
.setCoder(KvCoder.of(StringUtf8Coder.of(),AvroCoder.of(genericord.class,getSchema()))
//使用FileIO动态写入
.apply(FileIO.writeDynamic()
.by(elem->elem.getKey())//dest=KV元素中的键
.via(Contextful.fn(elem->elem.getValue()),//获取通用记录
Contextful.fn(dest->AvroIO.sink(getSchema()))
.withNumShards(1)//限制碎片数量
.to(options.getOutput())
.withNaming(key->FileIO.Write.defaultNaming(“results-”,key+“.avro”))
.withDestinationCoder(StringUtf8Coder.of());
p、 run().waitUntilFinish();
}
以下是将用于拆分文件的方法,其中定义了
items1
items2
以相同的键前缀和不同的后缀结束,这些后缀稍后将用于写入文件:

静态类SplitForFiles扩展DoFn{
@过程元素
公共无效处理元件(@Element KV元件,输出接收器){
字符串键=getCurrentTimeStamp();
Schema=getSchema();
对于(KV记录:element.getValue()){
GenericRecord item1=新的GenericData.Record(模式);
item1.put(“value”,record.getKey());
接收器输出(KV)(键+“-01”,第1项);
GenericRecord item2=新的GenericData.Record(模式);
item2.put(“value”,record.getValue().toString());
接收器输出(KV)(键+“-02”,第2项);
}
}
}
该键使用自定义方法
getCurrentTimeStamp()
,该方法检索时间戳最长为毫秒的字符串。这意味着,如果在同一毫秒内生成两个键这一不太可能发生的事件,则文件可能会有您期望的更多记录。如果此限制非常关键,那么我建议更改密钥的生成,您可以使用唯一标识符,甚至可以将其与上面提到的使用
FinishBundle
的方法相结合

在管道的最后,您可以看到,我曾经编写带有动态目标的Avro文件

这是一个使用相同模式编写Avro文件的简化示例,但您也可以将其用作编写更复杂管道的参考,例如,编写具有不同模式的文件