web-dev-qa-db-fra.com

Spark spécifiez plusieurs conditions de colonne pour la jointure de données

Comment donner plus de conditions de colonne lors de la jonction de deux images. Par exemple, je veux exécuter ce qui suit:

val Lead_all = Leads.join(Utm_Master,  
    Leaddetails.columns("LeadSource","Utm_Source","Utm_Medium","Utm_Campaign") ==
    Utm_Master.columns("LeadSource","Utm_Source","Utm_Medium","Utm_Campaign"),
"left")

Je veux rejoindre uniquement lorsque ces colonnes correspondent. Mais la syntaxe ci-dessus n'est pas valide car cols ne prend qu'une chaîne. Alors, comment puis-je obtenir ce que je veux.

43
user568109

Il existe un Spark jointure API de colonne/expression) pour un tel cas:

Leaddetails.join(
    Utm_Master, 
    Leaddetails("LeadSource") <=> Utm_Master("LeadSource")
        && Leaddetails("Utm_Source") <=> Utm_Master("Utm_Source")
        && Leaddetails("Utm_Medium") <=> Utm_Master("Utm_Medium")
        && Leaddetails("Utm_Campaign") <=> Utm_Master("Utm_Campaign"),
    "left"
)

L'opérateur <=> Dans l'exemple signifie " test d'égalité sans danger pour les valeurs NULL ".

La principale différence avec simple test d’égalité (===) Est que le premier est sûr à utiliser dans le cas où l’une des colonnes pourrait avoir une valeur nulle.

75
rchukh

À partir de Spark version 1.5.0 (qui n'est pas encore publiée), vous pouvez rejoindre plusieurs colonnes DataFrame. Reportez-vous à SPARK-7990: Ajouter des méthodes pour faciliter l'équi-jointure sur plusieurs colonnes joindre des clés .

Python

Leads.join(
    Utm_Master, 
    ["LeadSource","Utm_Source","Utm_Medium","Utm_Campaign"],
    "left_outer"
)

Scala

La question demandait une réponse Scala, mais je n'utilise pas Scala. Voici ma meilleure estimation ....

Leads.join(
    Utm_Master,
    Seq("LeadSource","Utm_Source","Utm_Medium","Utm_Campaign"),
    "left_outer"
)
15
dnlbrky

Une chose que vous pouvez faire est d'utiliser du SQL brut:

case class Bar(x1: Int, y1: Int, z1: Int, v1: String)
case class Foo(x2: Int, y2: Int, z2: Int, v2: String)

val bar = sqlContext.createDataFrame(sc.parallelize(
    Bar(1, 1, 2, "bar") :: Bar(2, 3, 2, "bar") ::
    Bar(3, 1, 2, "bar") :: Nil))

val foo = sqlContext.createDataFrame(sc.parallelize(
    Foo(1, 1, 2, "foo") :: Foo(2, 1, 2, "foo") ::
    Foo(3, 1, 2, "foo") :: Foo(4, 4, 4, "foo") :: Nil))

foo.registerTempTable("foo")
bar.registerTempTable("bar")

sqlContext.sql(
    "SELECT * FROM foo LEFT JOIN bar ON x1 = x2 AND y1 = y2 AND z1 = z2")
7
zero323

Dans Pyspark, vous pouvez simplement spécifier chaque condition séparément:

val Lead_all = Leads.join(Utm_Master,  
    (Leaddetails.LeadSource == Utm_Master.LeadSource) &
    (Leaddetails.Utm_Source == Utm_Master.Utm_Source) &
    (Leaddetails.Utm_Medium == Utm_Master.Utm_Medium) &
    (Leaddetails.Utm_Campaign == Utm_Master.Utm_Campaign))

Veillez simplement à utiliser correctement les opérateurs et les parenthèses.

6
Patricia F.

Scala:

Leaddetails.join(
    Utm_Master, 
    Leaddetails("LeadSource") <=> Utm_Master("LeadSource")
        && Leaddetails("Utm_Source") <=> Utm_Master("Utm_Source")
        && Leaddetails("Utm_Medium") <=> Utm_Master("Utm_Medium")
        && Leaddetails("Utm_Campaign") <=> Utm_Master("Utm_Campaign"),
    "left"
)

pour le rendre insensible à la casse,

import org.Apache.spark.sql.functions.{lower, upper}

puis utilisez simplement lower(value) dans la condition de la méthode join.

Par exemple: dataFrame.filter(lower(dataFrame.col("vendor")).equalTo("fortinet"))

5
Ani Menon

Le === _ options me donnent des colonnes dupliquées. J'utilise donc Seq à la place.

val Lead_all = Leads.join(Utm_Master,
    Seq("Utm_Source","Utm_Medium","Utm_Campaign"),"left")

Bien entendu, cela ne fonctionne que lorsque les noms des colonnes qui se joignent sont identiques.

2
Climbs_lika_Spyder

Essaye ça:

val rccJoin=dfRccDeuda.as("dfdeuda")
.join(dfRccCliente.as("dfcliente")
,col("dfdeuda.etarcid")===col("dfcliente.etarcid") 
&& col("dfdeuda.etarcid")===col("dfcliente.etarcid"),"inner")
0
Andy Quiroz

Spark SQL prend en charge la jointure sur plusieurs colonnes entre parenthèses, comme

... WHERE (list_of_columns1) = (list_of_columns2)

ce qui est un moyen plus court que de spécifier des expressions égales (=) pour chaque paire de colonnes combinées par un ensemble de "ET".

Par exemple:

SELECT a,b,c
FROM    tab1 t1
WHERE 
   NOT EXISTS
   (    SELECT 1
        FROM    t1_except_t2_df e
        WHERE (t1.a, t1.b, t1.c) = (e.a, e.b, e.c)
   )

au lieu de

SELECT a,b,c
FROM    tab1 t1
WHERE 
   NOT EXISTS
   (    SELECT 1
        FROM    t1_except_t2_df e
        WHERE t1.a=e.a AND t1.b=e.b AND t1.c=e.c
   )

ce qui est moins lisible, surtout quand la liste de colonnes est longue et que vous voulez traiter facilement les NULL.

0
Tagar