web-dev-qa-db-fra.com

Optimisation de la jointure DataFrame - Rejoindre le hachage de diffusion

J'essaie de joindre efficacement deux DataFrames, dont l'un est volumineux et le second, un peu plus petit.

Y a-t-il un moyen d'éviter tout ce brassage? Je ne peux pas définir autoBroadCastJoinThreshold, car il ne prend en charge que les entiers - et le tableau que je tente de diffuser est légèrement supérieur à un nombre entier d'octets.

Y a-t-il un moyen de forcer la diffusion en ignorant cette variable?

31
NNamed

Broadcast Hash Joins (similaire à jointure côté carte ou une combinaison côté carte dans Mapreduce):

Dans SparkSQL, vous pouvez voir le type de jointure en cours en appelant queryExecution.executedPlan. Comme avec le noyau Spark, si l’une des tables est beaucoup plus petite que l’autre, vous pouvez souhaiter une jointure de hachage de diffusion. Vous pouvez indiquer à Spark SQL qu'un DF donné doit être diffusé pour la jointure en appelant la méthode broadcast sur le DataFrame avant de le rejoindre

Exemple: largedataframe.join(broadcast(smalldataframe), "key")

en termes de DWH, où largedataframe peut ressembler à fait
smalldataframe peut ressembler à dimension

Comme décrit par mon livre préféré (HPS), les pls. voir ci-dessous pour avoir une meilleure compréhension .. enter image description here

Remarque: ci-dessus, broadcast provient de import org.Apache.spark.sql.functions.broadcast Et non de SparkContext.

Spark utilise également automatiquement le spark.sql.conf.autoBroadcastJoinThreshold Pour déterminer si un tableau doit être diffusé.

Conseil: voir la méthode DataFrame.explain ()

def
explain(): Unit
Prints the physical plan to the console for debugging purposes.

Existe-t-il un moyen de forcer la diffusion en ignorant cette variable?

sqlContext.sql("SET spark.sql.autoBroadcastJoinThreshold = -1")


NOTE:

Une autre note similaire hors de la boîte w.r.t. Hive (not spark): Une chose similaire peut être obtenue en utilisant Hive hint MAPJOIN comme ci-dessous ...

Select /*+ MAPJOIN(b) */ a.key, a.value from a join b on a.key = b.key

Hive> set Hive.auto.convert.join=true;
Hive> set Hive.auto.convert.join.noconditionaltask.size=20971520
Hive> set Hive.auto.convert.join.noconditionaltask=true;
Hive> set Hive.auto.convert.join.use.nonstaged=true;
Hive> set Hive.mapjoin.smalltable.filesize = 30000000; // default 25 mb made it as 30mb

Lectures supplémentaires: S'il vous plaît se référer mon article sur BHJ, SHJ, SMJ

67
Ram Ghadiyaram

Vous pouvez indiquer qu'un cadre de données doit être diffusé en utilisant left.join(broadcast(right), ...)

18
Sebastian Piu

Réglage spark.sql.autoBroadcastJoinThreshold = -1 désactivera complètement la diffusion. Voir Autres options de configuration dans Spark Guide SQL, DataFrames and Datasets) .

4
Vishal Gupta

C'est une limitation de courant d'étincelle, voir SPARK-6235 . La limite de 2 Go s'applique également aux variables de diffusion.

Etes-vous sûr qu’il n’ya pas d’autre moyen de le faire, par exemple partitionnement différent?

Sinon, vous pouvez y remédier en créant manuellement plusieurs variables de diffusion dont la valeur est inférieure à 2 Go.

3
dpeacock

J'ai trouvé ce code fonctionne pour Broadcast Join in Spark 2.11 version 2.0.0.

import org.Apache.spark.sql.functions.broadcast  

val employeesDF = employeesRDD.toDF
val departmentsDF = departmentsRDD.toDF

// materializing the department data
val tmpDepartments = broadcast(departmentsDF.as("departments"))

import context.implicits._

employeesDF.join(broadcast(tmpDepartments), 
   $"depId" === $"id",  // join by employees.depID == departments.id 
   "inner").show()

Voici la référence pour le code ci-dessus Blog de Henning Kropp, Broadcast Join avec Spark

1
SparkleGoat