web-dev-qa-db-ja.com

キー上のSparkデータフレームの結合

2つのデータフレームを構築しました。複数のSparkデータフレームを結合するにはどうすればよいですか?

例えば ​​:

PersonDfProfileDf共通​​列がpersonIdとして(キー)。 PersonDfProfileDfを組み合わせて1つのデータフレームを作成するにはどうすればよいですか?

36
Bindumalini KK

scala( を使用したエイリアスアプローチこれは、spark 2.xのsparkの古いバージョンの例です。他の回答を参照してください ):

ケースクラスを使用して、サンプルデータセットを準備できます。これはexのオプションです。hiveContext.sqlからDataFrameも取得できます。

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

私が個人的に好きではない一時テーブルのアプローチのサンプル...

DataFrameでregisterTempTable( tableName )メソッドを使用する理由は、Sparkが提供するDataFrameのメソッドを使用できることに加えて、使用するsqlContext.sql( sqlQuery )メソッドを介してSQLクエリを発行できるようにするためですSQLテーブルとしてのそのDataFrame。 tableNameパラメーターは、SQLクエリでそのDataFrameに使用するテーブル名を指定します。

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

結合についてもっと知りたい場合は、この素敵な投稿を参照してください: beyond-traditional-join-with-Apache-spark

enter image description here

注:1)@ RaphaelRothで述べたように、

val resultDf = PersonDf.join(ProfileDf,Seq("personId"))は、同じテーブルで内部結合を使用している場合、両側から重複する列がないため、適切なアプローチです。
2)Spark 2.xの例が別の回答で更新され、spark 2.xでサポートされる結合操作の完全なセットが追加され、例+結果が追加されました。

ヒント :

また、結合における重要なこと: ブロードキャスト関数はヒントを与えるのに役立ちます私の答えを参照してください

45
Ram Ghadiyaram

使用できます

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

またはより短くて柔軟(結合する複数の列を簡単に指定できるため)

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

一方通行

// 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")

別の方法

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

https://spark.Apache.org/docs/1.5.1/api/Java/org/Apache/spark/sql/DataFrame.html から、joinを使用します。

指定された列を使用する別のDataFrameとの内部等結合。

PersonDf.join(ProfileDf,$"personId")

OR

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

更新:

df.registerTempTable("tableName")を使用してDFsを一時テーブルとして保存し、sqlContextを使用してSQLクエリを作成することもできます。

1
Shankar