您可以使用Cloud Dataflow检测对象/文件名吗

时间:2018-08-04 11:48:00

标签: google-cloud-platform google-cloud-dataflow

我的用例是文件将以不同的格式上传到Cloud Storage。我的数据流管道会将文件/对象从csv / xml转换为json格式。在Dataflow中是否可以确定文件格式类型(即csv或xml),然后触发不同的逻辑进行相应处理?或者,是否可以确定文件名,然后我可以分析后缀以确定文件类型?

Thx

1 个答案:

答案 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是包含文件的文件夹的路径(没有*