web-dev-qa-db-ja.com

Spark Dataset API-join

Spark Dataset APIを使用しようとしていますが、単純な結合を行う際にいくつかの問題があります。

date | valueというフィールドを持つ2つのデータセットがあり、DataFrameの場合、私の結合は次のようになります。

val dfA : DataFrame
val dfB : DataFrame

dfA.join(dfB, dfB("date") === dfA("date") )

ただし、Datasetには.joinWithメソッドがありますが、同じアプローチは機能しません。

val dfA : Dataset
val dfB : Dataset

dfA.joinWith(dfB, ? )

.joinWithで必要な引数は何ですか?

20
mastro

joinWithを使用するには、最初にDataSetを作成する必要があり、おそらく2つを作成する必要があります。 DataSetを作成するには、スキーマに一致するケースクラスを作成し、Tがケースクラスである_DataFrame.as[T]_を呼び出す必要があります。そう:

_case class KeyValue(key: Int, value: String)
val df = Seq((1,"asdf"),(2,"34234")).toDF("key", "value")
val ds = df.as[KeyValue]
// org.Apache.spark.sql.Dataset[KeyValue] = [key: int, value: string]
_

ケースクラスをスキップして、タプルを使用することもできます。

_val tupDs = df.as[(Int,String)]
// org.Apache.spark.sql.Dataset[(Int, String)] = [_1: int, _2: string]
_

次に、次のように別のケースクラス/ DFがある場合:

_case class Nums(key: Int, num1: Double, num2: Long)
val df2 = Seq((1,7.7,101L),(2,1.2,10L)).toDF("key","num1","num2")
val ds2 = df2.as[Nums]
// org.Apache.spark.sql.Dataset[Nums] = [key: int, num1: double, num2: bigint]
_

次に、joinjoinWithの構文は似ていますが、結果は異なります。

_df.join(df2, df.col("key") === df2.col("key")).show
// +---+-----+---+----+----+
// |key|value|key|num1|num2|
// +---+-----+---+----+----+
// |  1| asdf|  1| 7.7| 101|
// |  2|34234|  2| 1.2|  10|
// +---+-----+---+----+----+

ds.joinWith(ds2, df.col("key") === df2.col("key")).show
// +---------+-----------+
// |       _1|         _2|
// +---------+-----------+
// | [1,asdf]|[1,7.7,101]|
// |[2,34234]| [2,1.2,10]|
// +---------+-----------+
_

ご覧のとおり、joinWithはオブジェクトをタプルの一部としてそのまま残しますが、joinは列を単一の名前空間にフラット化します。 (列名「キー」が繰り返されるため、上記の場合に問題が発生します。)

不思議なことに、df.col("key")df2.col("key")を使用して、dsと_ds2_を結合するための条件を作成する必要があります-col("key")どちらの側でも機能せず、ds.col(...)は存在しません。ただし、元のdf.col("key")を使用するとうまくいきます。

30
David Griffin

から https://docs.cloud.databricks.com/docs/latest/databricks_guide/05%20Spark/1%20Intro%20Datasets.html

あなたはちょうどできるように見えます

dfA.as("A").joinWith(dfB.as("B"), $"A.date" === $"B.date" )

上記の例では、以下のオプションを試すことができます-

  • 出力のケースクラスを定義する

    case class JoinOutput(key:Int, value:String, num1:Double, num2:Long)

  • 2つのデータセットを "Seq(" key ")"で結合します。これにより、出力で2つのキー列が重複するのを防ぐことができます。次のステップでケースクラスを適用するか、データを取得するのに役立ちます

    ds.join(ds2, Seq("key")).as[JoinOutput] res27: org.Apache.spark.sql.Dataset[JoinOutput] = [key: int, value: string ... 2 more fields]

    scala> ds.join(ds2, Seq("key")).as[JoinOutput].show +---+-----+----+----+ |key|value|num1|num2| +---+-----+----+----+ | 1| asdf| 7.7| 101| | 2|34234| 1.2| 10| +---+-----+----+----+

2
Syntax