En SQL standard, lorsque vous joignez une table à elle-même, vous pouvez créer des alias pour les tables afin de garder une trace des colonnes auxquelles vous faites référence:
SELECT a.column_name, b.column_name...
FROM table1 a, table1 b
WHERE a.common_field = b.common_field;
Il y a deux façons de penser à la même chose en utilisant l'API Spark DataFrame
:
Solution n ° 1: renommer les colonnes
Il existe deux méthodes différentes pour cela en réponse à cette question. Celui-ci renomme simplement toutes les colonnes avec un suffixe spécifique:
df.toDF(df.columns.map(_ + "_R"):_*)
Par exemple, vous pouvez faire:
df.join(df.toDF(df.columns.map(_ + "_R"):_*), $"common_field" === $"common_field_R")
Solution n ° 2: copiez la référence dans le DataFrame
Une autre solution simple consiste à simplement faire ceci:
val df: DataFrame = ....
val df_right = df
df.join(df_right, df("common_field") === df_right("common_field"))
Ces deux solutions fonctionnent et je pouvais voir que chacune d'elles était utile dans certaines situations. Y a-t-il des différences internes entre les deux dont je devrais être conscient?
Il y a au moins deux façons différentes d'approcher cela en créant un alias:
df.as("df1").join(df.as("df2"), $"df1.foo" === $"df2.foo")
ou en utilisant des jointures d'égalité basées sur le nom:
// Note that it will result in ambiguous column names
// so using aliases here could be a good idea as well.
// df.as("df1").join(df.as("df2"), Seq("foo"))
df.join(df, Seq("foo"))
En général, le changement de nom de colonne, bien que le plus laid, est la pratique la plus sûre dans toutes les versions. Il y a eu quelques bugs liés à la résolution des colonnes ( nous en avons trouvé un sur SO il n'y a pas si longtemps) et certains détails peuvent différer entre les analyseurs (HiveContext
/standard SQLContext
) si vous utilisez des expressions brutes.
Personnellement, je préfère utiliser des alias car leur ressemblance avec un SQL idiomatique et leur capacité à utiliser en dehors de la portée d'un objet DataFrame
spécifique.
En ce qui concerne les performances, sauf si vous êtes intéressé par un traitement en temps quasi réel, il ne devrait y avoir aucune différence de performances. Tous ces éléments devraient générer le même plan d'exécution.