web-dev-qa-db-fra.com

Jonction de Spark _ images sur la clé

J'ai construit deux dataframes. Comment pouvons-nous joindre plusieurs Spark dataframes?

Par exemple :

PersonDf, ProfileDf avec une colonne commune comme personId as (clé). Maintenant, comment pouvons-nous avoir un Dataframe combinant PersonDf et ProfileDf?

36
Bindumalini KK

Approche alias utilisant scala ( cet exemple est donné pour une version plus ancienne de spark pour spark 2.x voir mon autre réponse ):

Vous pouvez utiliser la classe de cas pour préparer un échantillon de données ... qui est facultatif par exemple: vous pouvez aussi obtenir DataFrame à partir de hiveContext.sql ..

import org.Apache.spark.sql.functions.col

case class Person(name: String, age: Int, personid : Int)

case class Profile(name: String, personid  : Int , profileDescription: String)

    val df1 = sqlContext.createDataFrame(
   Person("Bindu",20,  2) 
:: Person("Raphel",25, 5) 
:: Person("Ram",40, 9):: Nil)


val df2 = sqlContext.createDataFrame(
Profile("Spark",2,  "SparkSQLMaster") 
:: Profile("Spark",5, "SparkGuru") 
:: Profile("Spark",9, "DevHunter"):: Nil
)

// you can do alias to refer column name with aliases to  increase readablity

val df_asPerson = df1.as("dfperson")
val df_asProfile = df2.as("dfprofile")


val joined_df = df_asPerson.join(
    df_asProfile
, col("dfperson.personid") === col("dfprofile.personid")
, "inner")


joined_df.select(
  col("dfperson.name")
, col("dfperson.age")
, col("dfprofile.name")
, col("dfprofile.profileDescription"))
.show

exemple d'approche de table temporaire que je n'aime pas personnellement ...

La raison d'utiliser la méthode registerTempTable( tableName ) pour un DataFrame est que, en plus de pouvoir utiliser les méthodes fournies par Spark d'un DataFrame, vous pouvez également émettre des requêtes SQL via la méthode sqlContext.sql( sqlQuery ), qui utilisent ce DataFrame en tant que une table SQL. Le paramètre tableName spécifie le nom de la table à utiliser pour ce DataFrame dans les requêtes SQL.

df_asPerson.registerTempTable("dfperson");
df_asProfile.registerTempTable("dfprofile")

sqlContext.sql("""SELECT dfperson.name, dfperson.age, dfprofile.profileDescription
                  FROM  dfperson JOIN  dfprofile
                  ON dfperson.personid == dfprofile.personid""")

Si vous voulez en savoir plus sur les jointures, consultez ce billet de Nice: beyond-traditional-join-with-Apache-spark

enter image description here

Remarque: 1) Comme mentionné par @ RaphaelRoth ,

val resultDf = PersonDf.join(ProfileDf,Seq("personId")) est une bonne approche car il ne contient pas de colonnes dupliquées des deux côtés si vous utilisez une jointure interne avec la même table.
2) Exemple Spark 2.x mis à jour dans une autre réponse avec l'ensemble complet des opérations de jointure supportées par spark 2.x avec exemples + résultat

POINTE :

En outre, une chose importante dans les jointures: fonction de diffusion peut aider à donner un indice s'il vous plaît voir ma réponse

45
Ram Ghadiyaram

vous pouvez utiliser

val resultDf = PersonDf.join(ProfileDf, PersonDf("personId") === ProfileDf("personId"))

ou plus court et plus flexible (comme vous pouvez facilement spécifier plus de 1 colonnes pour rejoindre)

val resultDf = PersonDf.join(ProfileDf,Seq("personId"))
18
Raphael Roth

Une manière

// join type can be inner, left, right, fullouter
val mergedDf = df1.join(df2, Seq("keyCol"), "inner")
// keyCol can be multiple column names seperated by comma
val mergedDf = df1.join(df2, Seq("keyCol1", "keyCol2"), "left")

Autrement

import spark.implicits._ 
val mergedDf = df1.as("d1").join(df2.as("d2"), ($"d1.colName" === $"d2.colName"))
// to select specific columns as output
val mergedDf = df1.as("d1").join(df2.as("d2"), ($"d1.colName" === $"d2.colName")).select($"d1.*", $"d2.anotherColName")
3
Abu Shoeb

De https://spark.Apache.org/docs/1.5.1/api/Java/org/Apache/spark/sql/DataFrame.html , utilisez join:

Équi-jointure interne avec un autre DataFrame en utilisant la colonne donnée.

PersonDf.join(ProfileDf,$"personId")

OR

PersonDf.join(ProfileDf,PersonDf("personId") === ProfileDf("personId"))

Mise à jour:

Vous pouvez également enregistrer la DFs en tant que table temporaire à l'aide de df.registerTempTable("tableName") et vous pouvez écrire des requêtes SQL à l'aide de sqlContext.

1
Shankar