web-dev-qa-db-ja.com

Spark / scalaサイズのSQLクエリがInteger.MAX_VALUEを超えています

Sparkを使用して、S3イベントで簡単なSQLクエリを作成しようとしています。次のように〜30GBのJSONファイルをロードしています。

val d2 = spark.read.json("s3n://myData/2017/02/01/1234");
d2.persist(org.Apache.spark.storage.StorageLevel.MEMORY_AND_DISK);
d2.registerTempTable("d2");

次に、クエリの結果をファイルに書き込もうとしています:

val users_count = sql("select count(distinct data.user_id) from d2");
users_count.write.format("com.databricks.spark.csv").option("header", "true").save("s3n://myfolder/UsersCount.csv");

ただし、Sparkは次の例外をスローしています:

Java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE
at Sun.nio.ch.FileChannelImpl.map(FileChannelImpl.Java:869)
at org.Apache.spark.storage.DiskStore$$anonfun$getBytes$2.apply(DiskStore.scala:103)
at org.Apache.spark.storage.DiskStore$$anonfun$getBytes$2.apply(DiskStore.scala:91)
at org.Apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1287)
at org.Apache.spark.storage.DiskStore.getBytes(DiskStore.scala:105)
at org.Apache.spark.storage.BlockManager.getLocalValues(BlockManager.scala:439)
at org.Apache.spark.storage.BlockManager.getOrElseUpdate(BlockManager.scala:672)
at org.Apache.spark.rdd.RDD.getOrCompute(RDD.scala:330)
at org.Apache.spark.rdd.RDD.iterator(RDD.scala:281)
at org.Apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
at org.Apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:319)
at org.Apache.spark.rdd.RDD.iterator(RDD.scala:283)
at org.Apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
at org.Apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:319)
at org.Apache.spark.rdd.RDD.iterator(RDD.scala:283)
at org.Apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
at org.Apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:319)
at org.Apache.spark.rdd.RDD.iterator(RDD.scala:283)
at org.Apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:79)
at org.Apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:47)
at org.Apache.spark.scheduler.Task.run(Task.scala:85)
at org.Apache.spark.executor.Executor$TaskRunner.run(Executor.scala:274)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1142)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617)
at Java.lang.Thread.run(Thread.Java:745)

同じクエリが少量のデータでも機能することに注意してください。ここで問題は何ですか?

24
eexxoo

いいえSpark shuffleブロックは2GB(Integer.MAX_VALUEバイト)よりも大きくなる可能性があるため、より多くの/より小さなパーティションが必要です。

Spark.default.parallelismとspark.sql.shuffle.partitions(デフォルトは200)を調整して、パーティションの数が2GBの制限に達することなくデータを収容できるようにする必要があります(256GB /パーティションを目指して、200GBの場合は800を取得できます)パーティション)。数千のパーティションが非常に一般的であるため、推奨されるように1000にパーティションを再分割することを恐れないでください。

参考までに、rdd.getNumPartitions(d2.rdd.getNumPartitionsなど)を使用してRDDのパーティション数を確認できます。

さまざまな2GBの制限に対処する努力を追跡するためのストーリーがあります(しばらくの間公開されています): https://issues.Apache.org/jira/browse/SPARK-6235

このエラーの詳細については、 http://www.slideshare.net/cloudera/top-5-mistakes-to-avoid-when-writing-Apache-spark-applications/25 を参照してください。

57
Traian