web-dev-qa-db-fra.com

La requête SQL dans Spark / scala Size dépasse Integer.MAX_VALUE

J'essaie de créer une simple requête SQL sur les événements S3 à l'aide de Spark. Je charge ~ 30 Go de fichiers JSON comme suit:

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

Ensuite, j'essaie d'écrire dans un fichier le résultat de ma requête:

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");

Mais Spark lève l'exception suivante:

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)

Notez que la même requête fonctionne pour de plus petites quantités de données. Quel est le problème ici?

24
eexxoo

Non Spark peut être supérieur à 2 Go (octets Integer.MAX_VALUE), vous avez donc besoin de partitions plus/plus petites.

Vous devez ajuster spark.default.parallelism et spark.sql.shuffle.partitions (200 par défaut) de sorte que le nombre de partitions puisse accueillir vos données sans atteindre la limite de 2 Go (vous pouvez essayer de viser 256 Mo/partition, donc pour 200 Go, vous obtenez 800 partitions). Des milliers de partitions sont très courantes, alors n'ayez pas peur de repartitionner à 1000 comme suggéré.

Pour info, vous pouvez vérifier le nombre de partitions pour un RDD avec quelque chose comme rdd.getNumPartitions (c'est-à-dire d2.rdd.getNumPartitions)

Il y a une histoire pour suivre l'effort d'adresser les différentes limites de 2 Go (ouvert depuis un certain temps maintenant): https://issues.Apache.org/jira/browse/SPARK-6235

Voir http://www.slideshare.net/cloudera/top-5-mistakes-to-avoid-when-writing-Apache-spark-applications/25 pour plus d'informations sur cette erreur.

57
Traian