如何从Beam写入HDFS?

时间:2018-11-02 19:36:30

标签: apache-beam apache-beam-io

我正在尝试编写一个使用SparkRunner运行,从本地文件读取并写入HDFS的Beam管道。

这是一个最小的例子:

选项类-

package com.mycompany.beam.hdfsIOIssue;

import org.apache.beam.runners.spark.SparkPipelineOptions;
import org.apache.beam.sdk.io.hdfs.HadoopFileSystemOptions;
import org.apache.beam.sdk.options.Description;
import org.apache.beam.sdk.options.PipelineOptions;
import org.apache.beam.sdk.options.Validation;

public interface WritingToHDFSOptions extends PipelineOptions, SparkPipelineOptions, HadoopFileSystemOptions {

  @Validation.Required
  @Description("Path of the local file to read from")
  String getInputFile();
  void setInputFile(String value);

  @Validation.Required
  @Description("Path of the HDFS to write to")
  String getOutputFile();
  void setOutputFile(String value);

}

光束主类-

package com.mycompany.beam.hdfsIOIssue;

import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.io.FileBasedSink;
import org.apache.beam.sdk.io.TextIO;
import org.apache.beam.sdk.io.fs.ResourceId;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.values.PCollection;

public class WritingToHDFS {

  public static void main(String[] args) {
    PipelineOptionsFactory.register(WritingToHDFSOptions.class);

    WritingToHDFSOptions options = PipelineOptionsFactory.fromArgs(args).withValidation()
      .as(WritingToHDFSOptions.class);

    Pipeline p = Pipeline.create(options);

    buildPipeline(p, options);

    p.run();
  }

  static void buildPipeline(Pipeline p, WritingToHDFSOptions options) {
    PCollection<String> input = p.apply("ReadLines", TextIO.read().from(options.getInputFile()));

    ResourceId resource = FileBasedSink.convertToFileResourceIfPossible(options.getOutputFile());
    TextIO.Write write = TextIO.write().to(resource);
    input.apply("WriteLines", write);
  }
}

运行方式如下:

spark-submit test --master yarn --deploy-mode cluster --class com.mycompany.beam.hdfsIOIssue.WritingToHDFS my-project-bundled-0.1-SNAPSHOT.jar --runner=SparkRunner --inputFile=testInput --outputFile=hdfs://testOutput

我希望发生的事情:它将读取本地testInput文件中的行,并将它们写到我的hdfs主目录中的新文件中,名为testOutput。

实际上发生了什么:据我所知,什么也没有。 Spark说工作成功完成,并且我在日志中看到Beam步骤,但是没有将名为testOutput的文件或目录写入hdfs或本地目录。也许它是在spark executor节点上本地编写的,但是我无权检查它们。

我猜测要么我使用的TextIO接口错误,要么我需要做更多的事情来配置文件系统,而不仅仅是将其添加到我的PipelineOptions接口中。但是我找不到解释该操作方法的文档。

1 个答案:

答案 0 :(得分:1)

我认为您的选择应如下所示:

--inputFile=hdfs:///testInput --outputFile=hdfs:///testOutput

您可能还需要等到管道完成后才能看到结果:

p.run().waitUntilFinish();

您可以找到一个简单完整的HDFS写入示例(Avro文件)here

请注意(BEAM-2277)可能也适用,具体取决于您运行的Beam版本(它将引发错误)。您可以使用以下方法解决此问题:

TextIO.Write write = TextIO.write().to(resource)
  .withTempDirectory(FileSystems.matchNewResource("hdfs:///tmp/beam-test", true));

如果您在公共GitHub仓库上打包项目,我将对其进行测试并帮助您开始运行。