PySparkのJOINのhowオプション全部試してみた

joinのドキュメントを見るとhowのオプションには inner, cross, outer, full, fullouter, full_outer, left, leftouter, left_outer, right, rightouter, right_outer, semi, leftsemi, left_semi, anti, leftanti, left_antiがあるとのことなのでこれの結果を見ていこうと思います。

使用したSparkのバージョンは3.0.1です。

元データ

df0

+----+------+
|  id|value0|
+----+------+
|   1|     a|
|   2|  null|
|   3|     c|
|   4|     d|
|null|     e|
+----+------+

df1

+----+------+
|  id|value1|
+----+------+
|   1|     A|
|   2|     B|
|   3|  null|
|   5|  null|
|   6|     E|
|   7|  null|
|null|     G|
+----+------+

検証コード

howの部分(この場合はinner)を変えながら検証していきます。

df0 = spark.createDataFrame([
        (1, "a"),
        (2, None),
        (3, "c"),
        (4, "d"),
        (None, "e")
    ],
    ["id", "value0"])

df1 = spark.createDataFrame([
        (1, "A"),
        (2, "B"),
        (3, None),
        (5, None),
        (6, "E"),
        (7, None),
        (None, "G")
    ],
    ["id", "value1"])

df0.join(df1, "id", "inner").show()

howの種類

ドキュメント上は色々指定できるのですが、この部分を見ると

how 他バリエーション
fullouter outer, full, full_outer
leftouter left, left_outer
rightouter right, right_outer
leftsemi semi, left_semi
leftanti anti, left_anti

とのことなのでinner, fullouter, leftouter, rightouter, leftsemi, leftanti, crossを試していきます。

inner

df0、df1をidを基準に結合します。両方に存在する行のみのこります。 SQLだとINNER JOINに相当します。

+---+------+------+
| id|value0|value1|
+---+------+------+
|  1|     a|     A|
|  3|     c|  null|
|  2|  null|     B|
+---+------+------+

fullouter

df0、df1両方の行を削らず結合します。 SQLだとFULL OUTER JOINに相当します。

+----+------+------+
|  id|value0|value1|
+----+------+------+
|   7|  null|  null|
|null|     e|  null|
|null|  null|     G|
|   6|  null|     E|
|   5|  null|  null|
|   1|     a|     A|
|   3|     c|  null|
|   2|  null|     B|
|   4|     d|  null|
+----+------+------+

leftouter

df0を基準にdf1を結合します。 ちなみに、列の順番などは違いますがdf1.join(df0, "id", "rightouter")とした場合も同じデータが出力されます。 SQLだとLEFT OUTER JOINに相当します。

+----+------+------+
|  id|value0|value1|
+----+------+------+
|null|     e|  null|
|   1|     a|     A|
|   3|     c|  null|
|   2|  null|     B|
|   4|     d|  null|
+----+------+------+

rightouter

df1を基準にdf0を結合します。 ちなみに、列の順番などは違いますがdf1.join(df0, "id", "leftouter")とした場合も同じデータが出力されます。 SQLだとRIGHT OUTER JOINに相当します。

+----+------+------+
|  id|value0|value1|
+----+------+------+
|   7|  null|  null|
|null|  null|     G|
|   6|  null|     E|
|   5|  null|  null|
|   1|     a|     A|
|   3|     c|  null|
|   2|  null|     B|
+----+------+------+

leftsemi

df0にもdf1にもある行を抽出したdf0を返します。

+---+------+
| id|value0|
+---+------+
|  1|     a|
|  3|     c|
|  2|  null|
+---+------+

leftanti

df0にあってdf1に無い行を抽出したdf0を返します。

+----+------+
|  id|value0|
+----+------+
|null|     e|
|   4|     d|
+----+------+

cross

crossを設定するとUnsupported using join type Crossという例外が出てしまうので

df0.crossJoin(df1).show()

という様にcrossJoinメソッドを使いました。

※この例外に対してプルリクエストを出したところmasterにマージされたので3.1からはdf0.join(df1, None, "cross")とすれば使えるようになるはずです。

idに対して全てのコンビネーションの行を返します。 SQLだとCROSS JOINに相当します。

+---+------+----+------+
| id|value0|  id|value1|
+---+------+----+------+
|  1|     a|   1|     A|
|  1|     a|   2|     B|
|  1|     a|   3|  null|
|  1|     a|   5|  null|
|  1|     a|   6|     E|
|  1|     a|   7|  null|
|  1|     a|null|     G|
|  2|  null|   1|     A|
|  2|  null|   2|     B|
|  2|  null|   3|  null|
|  2|  null|   5|  null|
|  2|  null|   6|     E|
|  2|  null|   7|  null|
|  2|  null|null|     G|
|  3|     c|   1|     A|
|  3|     c|   2|     B|
|  3|     c|   3|  null|
|  3|     c|   5|  null|
|  3|     c|   6|     E|
|  3|     c|   7|  null|
+---+------+----+------+