我的用例是文件将以不同的格式上传到Cloud Storage。我的数据流管道会将文件/对象从csv / xml转换为json格式。在Dataflow中是否可以确定文件格式类型(即csv或xml),然后触发不同的逻辑进行相应处理?或者,是否可以确定文件名,然后我可以分析后缀以确定文件类型?
Thx
答案 0 :(得分:1)
使用FileIO.match()
将返回ReadableFile
个对象。如果我们记录一次匹配,则可以看到元数据包含resourceId
键值对中的文件名:
ReadableFile {metadata = Metadata {resourceId = gs://BUCKET_NAME/different/test1.csv, sizeBytes = 30,isReadSeekEfficient = true},compression = UNCOMPRESSED}
使用以下代码片段,我们可以创建键值对,其中键将是文件格式:
PCollection<KV<String, String>> filenames = p.apply("Read files", FileIO.match().filepattern(input))
.apply(FileIO.readMatches())
.apply(ParDo.of(new DoFn<ReadableFile, KV<String, String>>() {
@ProcessElement
public void process(ProcessContext c) {
// we'll output a KV where the file suffix is the key
String filename = c.element().getMetadata().resourceId().toString();
c.output(KV.of(filename.substring(filename.lastIndexOf('.') + 1), filename));
}
}));
从ProcessContext.getMetadata().resourceId()
中检索了文件名。 input
是匹配模式(即"gs://BUCKET_NAME/path/to/input/files/folder/*"
)
然后,我们可以根据密钥对文件进行不同的处理。在我的示例中,我只是根据数据类型写了一个不同的字符串:
filenames //
.apply("Process according to type", ParDo.of(new DoFn<KV<String, String>, String>() {
@ProcessElement
public void processElement(ProcessContext c) {
String key = c.element().getKey();
String value = c.element().getValue();
if (key.equals("csv")) {c.output("CSV - " + value.substring(value.lastIndexOf('/') + 1));}
else {c.output("XML - " + value.substring(value.lastIndexOf('/') + 1));}
}
}))//
.apply(TextIO.write().to(output).withoutSharding());
在我的情况下,结果文件将包含以下内容:
CSV - test1.csv
CSV - test2.csv
XML - test2.xml
XML - test1.xml
CSV - test3.csv
或者,您可以使用不同的匹配模式阅读它们,应用所需的转换,然后将结果展平。
pcl = pcl.and(
p.apply("Read CSV files", FileIO.match().filepattern(input + "*.csv"))
.apply(FileIO.readMatches())
.apply(ParDo.of(new DoFn<ReadableFile, KV<String, String>>() {
@ProcessElement
public void process(ProcessContext c) {
c.output(KV.of("csv", c.element().getMetadata().resourceId().toString()));
}
})))
.and(
p.apply("Read XML files", FileIO.match().filepattern(input + "*.xml"))
.apply(FileIO.readMatches())
.apply(ParDo.of(new DoFn<ReadableFile, KV<String, String>>() {
@ProcessElement
public void process(ProcessContext c){
c.output(KV.of("xml", c.element().getMetadata().resourceId().toString()));
}
})));
// combine/flatten all the PCollections together
PCollection<KV<String, String>> flattenedPCollection = pcl.apply(Flatten.pCollections());
在这种情况下,input
是包含文件的文件夹的路径(没有*
)