web-dev-qa-db-ja.com

どのようにしてAvroParquetWriterを使用し、AmazonS3 API経由でS3に書き込むことができますか?

現在、Avro経由で寄木細工を書くために以下のコードを使用しています。このコードはそれをファイルシステムに書き込みますが、S3に書き込みたいです。

try {
    StopWatch sw = StopWatch.createStarted();
    Schema avroSchema = AvroSchemaBuilder.build("pojo", message.getTransformedMessage().get(0));
    final String parquetFile = "parquet/data.parquet";
    final Path path = new Path(parquetFile);

    ParquetWriter writer = AvroParquetWriter.<GenericData.Record>builder(path)
        .withSchema(avroSchema)
        .withConf(new org.Apache.hadoop.conf.Configuration())
        .withCompressionCodec(CompressionCodecName.SNAPPY)
        .withWriteMode(Mode.OVERWRITE)//probably not good for prod. (overwrites files).
        .build();

    for (Map<String, Object> row : message.getTransformedMessage()) {
      StopWatch stopWatch = StopWatch.createStarted();
      final GenericRecord record = new GenericData.Record(avroSchema);
      row.forEach((k, v) -> {
        record.put(k, v);
      });
      writer.write(record);
    }
    //todo:  Write to S3.  We should probably write via the AWS objects.  This does not show that.
    //https://stackoverflow.com/questions/47355038/how-to-generate-parquet-file-using-pure-Java-including-date-decimal-types-an
    writer.close();
    System.out.println("Total Time: " + sw);

  } catch (Exception e) {
    //do somethign here.  retryable?  non-retryable?  Wrap this excetion in one of these?
    transformedParquetMessage.getOriginalMessage().getMetaData().addException(e);
  }

これは問題なくファイルに書き込みますが、AmazonS3 apiにストリーミングするにはどうすればよいですか? Hadoop-aws jarを使用してWeb上でいくつかのコードを見つけましたが、そのためにはいくつかのWindows exeファイルが必要であり、もちろんそれを避けたいと考えています。現在使用しているのは次のものだけです。

 <dependency>
  <groupId>org.Apache.avro</groupId>
  <artifactId>avro</artifactId>
  <version>1.9.2</version>
</dependency>
<dependency>
  <groupId>org.Apache.parquet</groupId>
  <artifactId>parquet-avro</artifactId>
  <version>1.8.1</version>
</dependency>
<dependency>
  <groupId>org.Apache.hadoop</groupId>
  <artifactId>hadoop-core</artifactId>
  <version>1.2.1</version>
</dependency>

だから問題は、AvroParquetWriterで出力ストリームをインターセプトしてS3にストリーミングできるようにする方法があるのですか?私がやりたい主な理由これは再試行用です。 S3は自動的に最大3回再試行します。これは私たちを大いに助けてくれるでしょう。

5
markthegrea

これはhadoop-aws jarに依存しているため、使用したくない場合は、私がお手伝いできるかどうか確信が持てません。ただし、私はMacで実行していて、Windows exeファイルがないので、それらがどこから来ているのかわかりません。 AvroParquetWriterはすでにHadoopに依存しているため、この追加の依存関係が受け入れられない場合でも、他の人には大した問題ではない可能性があります。

AvroParquetWriterを使用して、URIパラメーターで作成されたHadoopパスを渡し、適切な構成を設定することにより、S3に直接ストリーミングできます。

val uri = new URI("s3a://<bucket>/<key>")
val path = new Path(uri)

val config = new Configuration()
config.set("fs.s3a.access.key", key)
config.set("fs.s3a.secret.key", secret)
config.set("fs.s3a.session.token", sessionToken)
config.set("fs.s3a.aws.credentials.provider", credentialsProvider)

val writer = AvroParquetWriter.builder[GenericRecord](path).withConf(config).withSchema(schema).build()

次の依存関係を使用しました(sbt形式):

"org.Apache.avro" % "avro" % "1.8.1"
"org.Apache.hadoop" % "hadoop-common" % "2.9.0"
"org.Apache.hadoop" % "hadoop-aws" % "2.9.0"
"org.Apache.parquet" % "parquet-avro" % "1.8.1"
1
john_s

うまくいけば、私は質問を誤解していませんが、ここであなたがしていることはavroを寄木細工に変換することであり、その寄木細工をs3にアップロードしたいと思います

ParquetWriterを閉じた後、次のようなメソッドを呼び出す必要があります(これにより、avroからparquetへのストリームの書き込みがインターセプトされず、書き込みが行われなくなったParquetファイルがストリーミングされるだけです)。

        AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"))).build();
        S3Path outputPath = new S3Path();
        outputPath.setBucket("YOUR_BUCKET");
        outputPath.setKey("YOUR_FOLDER_PATH");
        try {
            InputStream parquetStream = new FileInputStream(new File(parquetFile));
            s3Client.putObject(outputPath.getBucket(), outputPath.getKey(), parquetStream, null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

aWS SDKの使用

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-Java-sdk</artifactId>
    <version>1.11.749</version>
</dependency>

もちろん、メソッドは別のutilsクラスに常駐し、このメソッドのコンストラクターはAmazonS3 s3Clientを認証情報で初期化する必要があるため、実行する必要があるのは、オブジェクトを配置するためにそのs3Clientメンバーを呼び出してアクセスすることだけです。

お役に立てれば

0
Thecodeanator