web-dev-qa-db-ja.com

Sparkで大きなgzip圧縮ファイルを処理する

AWS EMRでSparkを使用して処理しようとしているs3からの大きな(約85 GB圧縮)gzip圧縮ファイルがあります(現在m4.xlargeマスターインスタンスと2つのm4.10xlargeコアを使用)それぞれ100 GBのEBSボリュームを持つインスタンスです。gzipは分割不可能なファイル形式であり、 I'veseenit推奨 Sparkは最初に1つのパーティションを持つRDDを提供するため、圧縮ファイルを再パーティション化する必要があります。ただし、実行後

scala> val raw = spark.read.format("com.databricks.spark.csv").
     | options(Map("delimiter" -> "\\t", "codec" -> "org.Apache.hadoop.io.compress.GzipCodec")).
     | load("s3://path/to/file.gz").
     | repartition(sc.defaultParallelism * 3)
raw: org.Apache.spark.sql.Dataset[org.Apache.spark.sql.Row] = [_c0: string, _c1: string ... 48 more fields
scala> raw.count()

SparkアプリケーションUI、まだ1つのタスクで1つのアクティブなエグゼキューター(他の14は死んでいる)だけが表示され、ジョブが完了しない(または少なくともそれができるのに十分な時間待った)。

  • ここで何が起こっているのですか?誰かがこの例でSparkがどのように機能しているかを理解するのを手伝ってくれませんか?
  • 別のクラスター構成を使用する必要がありますか?
  • 残念ながら、私は圧縮モードを制御できませんが、そのようなファイルを処理する別の方法はありますか?
12
user4601931

ファイル形式が分割可能でない場合、1つのコアでファイル全体を読み取ることを回避する方法はありません。作業を並列化するには、作業のチャンクを異なるコンピューターに割り当てる方法を知っている必要があります。 gzipの場合、128Mのチャンクに分割するとします。 n番目のチャンクは、解凍方法を知るためにn-1番目のチャンクの位置情報に依存します。これは、n-2番目のチャンクに依存し、以下同様です。

並列化する場合は、このファイルを分割可能にする必要があります。 1つの方法は、それを解凍して非圧縮で処理することです。または、解凍して複数のファイル(必要な並列タスクごとに1つのファイル)に分割し、各ファイルをgzipすることもできます。

7
Tim

Sparkは、単一のgzipファイルの読み取りを並列化できます。

あなたができる最善の方法は、gzipされたチャンクに分割することです。

ただし、Sparkはgzipファイルの読み取りが非常に遅いです。これを行うと、速度を上げることができます。

file_names_rdd = sc.parallelize(list_of_files, 100)
lines_rdd = file_names_rdd.flatMap(lambda _: gzip.open(_).readlines())

Pythonは2倍高速ですが、ネイティブのSpark gzipリーダーを読み取るよりも高速です。

0
Mathieu Longtin

私はこの問題に直面しており、これが解決策です。

この問題に対処する最良の方法は、Sparkバッチ実行の前に.gzファイルを解凍することです。次に、この解凍ファイルを使用します。その後、Spark parallelismを使用できます。 。

.gzファイルを解凍するコード。

import gzip
import shutil
with open('file.txt.gz', 'rb') as f_in, gzip.open('file.txt', 'wb') as f_out:
    shutil.copyfileobj(f_in, f_out)
0
Amol More