web-dev-qa-db-ja.com

Spark + Parquet + Snappy:全体の圧縮率はspark

コミュニティ!

Sparkで圧縮率を向上させる方法を教えてください。

ケースを説明しましょう:

  1. 私はデータセットを持っています、それをSqoop ImportTool as-parquet-file using codec snappyを使用してインポートされたHDFSではproductと呼びましょう。インポートの結果、合計46 GBのファイルが100個あり、サイズが異なる(最小11MB、最大1.5GB、平均〜500MB)ファイルがあります。 80十億を少し超えるレコードの合計数84列

  2. Spark using snappyを使用して簡単な読み取り/再パーティション/書き込みを実行しているため、次のようになります。

100 GB同じファイル数、同じコーデック、同じ数、同じ列での出力サイズ。

コードスニペット:

val productDF = spark.read.parquet("/ingest/product/20180202/22-43/")

productDF
.repartition(100)
.write.mode(org.Apache.spark.sql.SaveMode.Overwrite)
.option("compression", "snappy")
.parquet("/processed/product/20180215/04-37/read_repartition_write/general")
  1. Parquet-toolsを使用して、取り込みと処理の両方からランダムファイルを調べたところ、以下のようになりました。

摂取:

creator:                        parquet-mr version 1.5.0-cdh5.11.1 (build ${buildNumber}) 
extra:                          parquet.avro.schema = {"type":"record","name":"AutoGeneratedSchema","doc":"Sqoop import of QueryResult","fields"

and almost all columns looks like
AVAILABLE: OPTIONAL INT64 R:0 D:1

row group 1:                    RC:3640100 TS:36454739 OFFSET:4 

AVAILABLE:                       INT64 SNAPPY DO:0 FPO:172743 SZ:370515/466690/1.26 VC:3640100 ENC:RLE,PLAIN_DICTIONARY,BIT_PACKED ST:[min: 126518400000, max: 1577692800000, num_nulls: 2541633]

処理済み:

creator:                        parquet-mr version 1.5.0-cdh5.12.0 (build ${buildNumber}) 
extra:                          org.Apache.spark.sql.parquet.row.metadata = {"type":"struct","fields"

AVAILABLE:                      OPTIONAL INT64 R:0 D:1
...

row group 1:                    RC:6660100 TS:243047789 OFFSET:4 

AVAILABLE:                       INT64 SNAPPY DO:0 FPO:4122795 SZ:4283114/4690840/1.10 VC:6660100 ENC:BIT_PACKED,PLAIN_DICTIONARY,RLE ST:[min: -2209136400000, max: 10413820800000, num_nulls: 4444993]

一方、再パーティション化や合体を使用しない場合、サイズは取り込みデータサイズに近いままです。

  1. 今後、私は次のことを行いました:

    • データセットを読み取って書き戻す

      productDF
        .write.mode(org.Apache.spark.sql.SaveMode.Overwrite)
        .option("compression", "none")
        .parquet("/processed/product/20180215/04-37/read_repartition_write/nonewithoutshuffle")
      
    • データセットを読み取り、パーティションを分割して書き戻す

      productDF
        .repartition(500)
        .write.mode(org.Apache.spark.sql.SaveMode.Overwrite)
        .option("compression", "none")
        .parquet("/processed/product/20180215/04-37/read_repartition_write/nonewithshuffle")
      

結果:80 GBなしおよび283 GB出力ファイルの同じ数の再パーティション化あり

80GB寄木細工のメタの例:

AVAILABLE:                       INT64 UNCOMPRESSED DO:0 FPO:456753 SZ:1452623/1452623/1.00 VC:11000100 ENC:RLE,PLAIN_DICTIONARY,BIT_PACKED ST:[min: -1735747200000, max: 2524550400000, num_nulls: 7929352]

283 GBの寄木細工のメタの例:

AVAILABLE:                       INT64 UNCOMPRESSED DO:0 FPO:2800387 SZ:2593838/2593838/1.00 VC:3510100 ENC:RLE,PLAIN_DICTIONARY,BIT_PACKED ST:[min: -2209136400000, max: 10413820800000, num_nulls: 2244255]

圧縮されていないデータがなくても、その寄木細工自体(エンコードあり?)はデータのサイズを大幅に削減するようです。どうやって ? :)

非圧縮の80 GBを読み取って、パーティションを再作成して書き戻しました-283 GBあります

  • 最初の質問は、spark repartitioning/shuffle?

  • 2番目は、sparkでデータを効率的にシャッフルして、寄せ木細工のエンコード/圧縮がある場合にそれを利用する方法です。

一般に、何も変更しなかったとしても、spark処理後にデータサイズが大きくなることは望ましくありません。

また、私は見つけられませんでした、snappyの構成可能な圧縮率はありますか? -1 ... -9?私が知っているように、gzipにはこれがありますが、Spark/Parquetライターでこのレートを制御する方法は何ですか?

どんな助けにも感謝します!

ありがとう!

7
Mikhail Dubkov

データフレームでrepartition(n)を呼び出すと、ラウンドロビン分割が行われます。再パーティション化する前に存在していたデータの局所性は失われ、エントロピーは増加しました。そのため、ランレングスとディクショナリエンコーダー、および圧縮コーデックは、実際に操作する必要はあまりありません。

そのため、パーティションを再作成するときは、repartition (n, col)バージョンを使用する必要があります。データの局所性を保持する適切な列を与えます。

また、ダウンストリームジョブ用にsqoopedテーブルを最適化している可能性があるため、スキャンを高速化するためにsortWithinPartitionを実行できます。

df.repartition(100, $"userId").sortWithinPartitions("userId").write.parquet(...)

3
user1509458