Je crée un nouveau DataFrame avec une poignée d'enregistrements d'une jointure.
val joined_df = first_df.join(second_df, first_df.col("key") ===
second_df.col("key") && second_df.col("key").isNull, "left_outer")
joined_df.repartition(1)
joined_df.cache()
joined_df.count()
Tout est rapide (moins d'une seconde) sauf l'opération de comptage. La conversion RDD entre en action et prend littéralement des heures pour se terminer. Existe-t-il un moyen d'accélérer les choses?
INFO MemoryStore: Block rdd_63_140 stored as values in memory (estimated size 16.0 B, free 829.3 MB)
INFO BlockManagerInfo: Added rdd_63_140 in memory on 192.168.8.52:36413 (size: 16.0 B, free: 829.8 MB)
INFO Executor: Finished task 140.0 in stage 10.0 (TID 544). 4232 bytes result sent to driver
INFO TaskSetManager: Starting task 142.0 in stage 10.0 (TID 545, localhost, executor driver, partition 142, PROCESS_LOCAL, 6284 bytes)
INFO Executor: Running task 142.0 in stage 10.0 (TID 545)
INFO TaskSetManager: Finished task 140.0 in stage 10.0 (TID 544) in 16 ms on localhost (executor driver) (136/200)
INFO ShuffleBlockFetcherIterator: Getting 0 non-empty blocks out of 200 blocks
INFO ShuffleBlockFetcherIterator: Started 0 remote fetches in 0 ms
INFO ShuffleBlockFetcherIterator: Getting 0 non-empty blocks out of 200 blocks
INFO ShuffleBlockFetcherIterator: Started 0 remote fetches in 0 ms
Tout est rapide (moins d'une seconde) sauf l'opération de comptage.
Ceci est justifié comme suit: toutes les opérations avant les count
sont appelées transformations et ce type d'opérations spark sont paresseux c'est-à-dire qu'il ne fait aucun calcul avant d'appeler une action (count
dans votre exemple).
Le deuxième problème est dans la repartition(1)
:
gardez à l'esprit que vous perdrez tout le parallélisme offert par spark et votre calcul sera exécuté dans un exécuteur (noyau si vous êtes en mode autonome), vous devez donc supprimer cette étape ou modifier 1 à un nombre propositionnel au nombre de cœurs de votre CPU (mode autonome) ou au nombre d'exécuteurs (mode cluster).
La conversion RDD entre en jeu et prend littéralement des heures pour se terminer.
Si je comprends bien, vous convertiriez le DataFrame
en RDD
, c'est vraiment une mauvaise pratique dans spark et vous devriez éviter une telle conversion aussi possible que vous c'est parce que les données dans DataFrame
et Dataset
sont encodées en utilisant special spark encoders (ça s'appelle tungstant si je s'en souviennent) qui prennent beaucoup moins de mémoire que les encodeurs de sérialisation JVM, donc une telle conversion signifie que spark changera le type de vos données par les siens (qui prennent beaucoup moins de mémoire) et laissez spark optimiser beaucoup de commutations en travaillant simplement les données encodées et non en sérialisant les données avec lesquelles travailler et puis en les désérialisant) vers les données JVM tapez et c'est pourquoi DataFrame
s et Dataset
s sont très puissants que RDD
s
J'espère que cela vous aidera
Comme d'autres l'ont mentionné, les opérations avant count
sont "paresseuses" et seules enregistrent une transformation , plutôt qu'en réalité force un calcul .
Lorsque vous appelez count
, le calcul est déclenché. C'est lorsque Spark lit vos données, effectue toutes les transformations précédemment enregistrées et calcule le résultat que vous avez demandé (dans ce cas, un count
).
La conversion RDD démarre et prend littéralement des heures
Je pense que le terme "conversion" est peut-être un peu inexact. Ce qui se passe réellement, c'est que les transformations DataFrame
que vous avez enregistrées sont traduites en opérations RDD
, et elles sont appliquées au RDD qui sous-tend votre DataFrame
. Il n'y a pas de conversion en soi dans le code que vous avez donné ici.
En passant, il est possible de convertir explicitement un DataFrame
en RDD
via le DataFrame.rdd
propriété. Comme mentionné dans cette réponse c'est généralement une mauvaise idée, car vous perdez certains des avantages (à la fois en termes de performances et d'API) d'avoir des données bien structurées.