我正在尝试将特定文件从存储桶A复制到存储桶B。存储桶A是结构化的(目录),而存储桶B将没有目录。面临的挑战是,我需要根据文件的原始文件名命名。通常,我会创建一个自定义文件名策略并根据需要对其进行修改。但是,我知道访问原始文件名的唯一方法是通过每个元素并提取其元数据。如何获得对TextIO.write中每个元素的访问权限?
我已经考虑过在TextIO.write之前创建一个转换,该转换接受元素的集合并输出KV的集合,其中键是原始文件名,值是元素(similar to this example)。但是,如果我这样做了,我的作家怎么知道怎么写KV?
通过使用writedynamic并按可序列化函数中每个元素的文件名进行分区,我能够获得这种破解方式。然后,我可以将partitiontype传递给我的文件名策略,然后实现所需的结果。话虽这么说,这似乎远非高效,并且不是为此而设计的,因为我实际上不需要分区任何东西。
答案 0 :(得分:1)
您可能希望考虑以下几种方法,具体取决于您是尝试一次性复制还是创建某种方式来执行此系统:
如果您只是想复制文件。然后,您可能根本不需要数据流。您可以使用gsutil复制文件。
如果您只需要复制文件而无需修改,而仍然想使用数据流,则可以自己在数据流中使用gsutil。
如果需要转换每个文件。您可能要进行转换,使其对整个文件起作用,将其完全读取并完全修改,然后在自定义ParDo中写出。 Example
或者使用数据流。每当创建GCS文件时,您都可以使用Google cloud functions to trigger。
注意:TextIO和FileIO是基于记录的转换,而不是基于文件的转换。他们将文件应用程序放入记录中,以实现并行性。原始文件名和记录顺序实际上并未得到维护。我看到您尝试过使用KV维护文件名,但是正如您提到的,FileIO不允许您将每条记录都传递给文件名。
答案 1 :(得分:0)
使用writeDynamic
时,by
方法指定用于将传入数据划分到其相应目标的标准。例如,如果这是根据KV对的键决定的,则可以使用.by(KV::getKey)
,而由于.withNaming
可以调整目标文件名。
此外,使用via
方法,我们可以提供一个要应用到每个分区的功能,如here所述。在这种情况下,我们想使用键来选择目标,但是我们不想在输出文件中写入它们。因此,我们可以写出值并用.via(Contextful.fn(KV::getValue), TextIO.sink())
省略键。
尽管by
接受SerializableFunction
作为参数,但是via
方法要求使用Contextful<Contextful.Fn<UserT,OutputT>> outputFn
。这就是为什么我将KV::getValue
包装在Contextful.fn()
中的原因。在诸如this template之类的示例中,提供上下文(如所需的侧面输入)可能会很有用,但在这里我只想传递该函数。
代码段(更多详细信息here)
p.apply("Create Data", Create.of(KV.of("one", "this is row 1"), KV.of("two", "this is row 2"), KV.of("three", "this is row 3"), KV.of("four", "this is row 4")))
.apply(FileIO.<String, KV<String, String>>writeDynamic()
.by(KV::getKey)
.withDestinationCoder(StringUtf8Coder.of())
.via(Contextful.fn(KV::getValue), TextIO.sink())
.to(output)
.withNaming(key -> FileIO.Write.defaultNaming("file-" + key, ".txt")));
答案 2 :(得分:0)
我遇到了java.lang.IllegalArgumentException的错误:当我尝试运行以下代码时,无法反序列化FileBasedSink:
public static void main(String[] args) {
WordCountOptions options = PipelineOptionsFactory.fromArgs(args).withValidation().as(WordCountOptions.class);
Pipeline p = Pipeline.create(options);
p.apply("Create Data", Create.of(KV.of("one", "this is row 1"), KV.of("two", "this is row 2"), KV.of("three", "this is row 3"), KV.of("four", "this is row 4")))
.apply(FileIO.<String, KV<String, String>>writeDynamic()
.by(KV::getKey)
.withDestinationCoder(StringUtf8Coder.of())
.via(Contextful.fn(KV::getValue), TextIO.sink())
.to("a")
.withNaming(key -> FileIO.Write.defaultNaming("file-" + key, ".txt")));
p.run().waitUntilFinish();
}
可以请您帮忙吗?
谢谢