web-dev-qa-db-ja.com

Spark Dataframe Nested Case Whenステートメント

Spark DataFrameに以下のSQLロジックを実装する必要があります

SELECT KEY,
    CASE WHEN tc in ('a','b') THEN 'Y'
         WHEN tc in ('a') AND amt > 0 THEN 'N'
         ELSE NULL END REASON,
FROM dataset1;

私の入力DataFrameは次のとおりです。

val dataset1 = Seq((66, "a", "4"), (67, "a", "0"), (70, "b", "4"), (71, "d", "4")).toDF("KEY", "tc", "amt")

dataset1.show()
+---+---+---+
|KEY| tc|amt|
+---+---+---+
| 66|  a|  4|
| 67|  a|  0|
| 70|  b|  4|
| 71|  d|  4|
+---+---+---+

ネストされたcase whenステートメントを次のように実装しました。

dataset1.withColumn("REASON", when(col("tc").isin("a", "b"), "Y")
  .otherwise(when(col("tc").equalTo("a") && col("amt").geq(0), "N")
    .otherwise(null))).show()
+---+---+---+------+
|KEY| tc|amt|REASON|
+---+---+---+------+
| 66|  a|  4|     Y|
| 67|  a|  0|     Y|
| 70|  b|  4|     Y|
| 71|  d|  4|  null|
+---+---+---+------+

「otherwise」ステートメントを使用した上記のロジックの可読性は、ネストされたwhenステートメントがさらに進んだ場合、少し乱雑になります。

Spark DataFrames?のステートメントの場合、ネストされたケースを実装するより良い方法はありますか?

8
RaAm

ここにはネストがないため、otherwiseは必要ありません。必要なのは、チェーンされたwhen

import spark.implicits._

when($"tc" isin ("a", "b"), "Y")
  .when($"tc" === "a" && $"amt" >= 0, "N")

ELSE NULLは暗黙的であるため、完全に省略することができます。

使用するパターンは、データ構造上のfoldingにより適しています。

val cases = Seq(
  ($"tc" isin ("a", "b"), "Y"),
  ($"tc" === "a" && $"amt" >= 0, "N")
)

ここで、when-otherwiseは再帰パターンに自然に従い、nullは基本ケースを提供します。

cases.foldLeft(lit(null)) {
  case (acc, (expr, value)) => when(expr, value).otherwise(acc)
}

この一連の条件では、「N」の結果に到達することは不可能であることに注意してください。 tcが「a」に等しい場合、最初の句によってキャプチャされます。そうでない場合は、両方の述部を満たすことができず、デフォルトはNULLになります。むしろ:

when($"tc" === "a" && $"amt" >= 0, "N")
 .when($"tc" isin ("a", "b"), "Y")
17
user6910411

より複雑なロジックの場合、読みやすくするためにUDFを使用することを好みます。

val selectCase = udf((tc: String, amt: String) =>
  if (Seq("a", "b").contains(tc)) "Y"
  else if (tc == "a" && amt.toInt <= 0) "N"
  else null
)


dataset1.withColumn("REASON", selectCase(col("tc"), col("amt")))
  .show
3
Raphael Roth

データセットでselectExprを使用するだけです

dataset1.selectExpr("*", "CASE WHEN tc in ('a') AND amt > 0 THEN 'N' WHEN tc in ('a','b') THEN 'Y' ELSE NULL END
REASON").show()

+---+---+---+------+
|KEY| tc|amt|REASON|
+---+---+---+------+
| 66|  a|  4|     N|
| 67|  a|  0|     Y|
| 70|  b|  4|     Y|
| 71|  d|  4|  null|
+---+---+---+------+

最初の条件はより一般的な条件であるため、2番目の条件は最初の条件の前に配置する必要があります。

Tc in( 'a')AND amt> 0 THEN 'N'の場合

0
PoojanKothari