J'ai besoin de join
de nombreux DataFrames ensemble sur la base de certaines colonnes de clés partagées. Pour un RDD de valeur-clé, on peut spécifier un partitionneur afin que les points de données avec la même clé soient mélangés au même exécuteur afin que la jonction soit plus efficace (si l'on a des opérations liées au mélange avant le join
). Peut-on faire la même chose sur Spark DataFrames ou DataSets?
Vous pouvez repartition
un DataFrame après l'avoir chargé si vous savez que vous le rejoindrez plusieurs fois
val users = spark.read.load("/path/to/users").repartition('userId)
val joined1 = users.join(addresses, "userId")
joined1.show() // <-- 1st shuffle for repartition
val joined2 = users.join(salary, "userId")
joined2.show() // <-- skips shuffle for users since it's already been repartitioned
Il va donc mélanger les données une fois, puis réutiliser les fichiers de mélange lors de la jointure des heures suivantes.
Cependant, si vous savez que vous mélangerez à plusieurs reprises des données sur certaines clés, le mieux serait d'enregistrer les données sous forme de tableaux regroupés. Cela écrira les données déjà pré-hachées partitionnées, donc lorsque vous lisez les tables et les joignez, vous évitez le shuffle. Vous pouvez le faire comme suit:
// you need to pick a number of buckets that makes sense for your data
users.bucketBy(50, "userId").saveAsTable("users")
addresses.bucketBy(50, "userId").saveAsTable("addresses")
val users = spark.read.table("users")
val addresses = spark.read.table("addresses")
val joined = users.join(addresses, "userId")
joined.show() // <-- no shuffle since tables are co-partitioned
Afin d'éviter un mélange, les tables doivent utiliser le même regroupement (par exemple, le même nombre de regroupements et la jonction sur les colonnes de regroupement).
Il est possible d'utiliser l'API DataFrame/DataSet en utilisant la méthode repartition
. En utilisant cette méthode, vous pouvez spécifier une ou plusieurs colonnes à utiliser pour le partitionnement des données, par exemple.
val df2 = df.repartition($"colA", $"colB")
Il est également possible de spécifier en même temps le nombre de partitions souhaitées dans la même commande,
val df2 = df.repartition(10, $"colA", $"colB")
Remarque: cela ne garantit pas que les partitions pour les dataframes seront situées sur le même noeud, seulement que le partitionnement se fait de la même manière.