コミュニティ!
Sparkで圧縮率を向上させる方法を教えてください。
ケースを説明しましょう:
私はデータセットを持っています、それをSqoop ImportTool as-parquet-file using codec snappyを使用してインポートされたHDFSではproductと呼びましょう。インポートの結果、合計46 GBのファイルが100個あり、サイズが異なる(最小11MB、最大1.5GB、平均〜500MB)ファイルがあります。 80十億を少し超えるレコードの合計数84列
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")
摂取:
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]
一方、再パーティション化や合体を使用しない場合、サイズは取り込みデータサイズに近いままです。
今後、私は次のことを行いました:
データセットを読み取って書き戻す
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ライターでこのレートを制御する方法は何ですか?
どんな助けにも感謝します!
ありがとう!
データフレームでrepartition(n)
を呼び出すと、ラウンドロビン分割が行われます。再パーティション化する前に存在していたデータの局所性は失われ、エントロピーは増加しました。そのため、ランレングスとディクショナリエンコーダー、および圧縮コーデックは、実際に操作する必要はあまりありません。
そのため、パーティションを再作成するときは、repartition (n, col)
バージョンを使用する必要があります。データの局所性を保持する適切な列を与えます。
また、ダウンストリームジョブ用にsqoopedテーブルを最適化している可能性があるため、スキャンを高速化するためにsortWithinPartition
を実行できます。
df.repartition(100, $"userId").sortWithinPartitions("userId").write.parquet(...)