web-dev-qa-db-fra.com

Données de partition pour une jonction efficace pour Spark dataframe / dataset

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?

6
Rainfield

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).

12
Silvio

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.