Necesito para implementar la siguiente lógica SQL en la Chispa de la DataFrame

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;

Mi entrada DataFrame es la siguiente:

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|
+---+---+---+

Tengo implementar el anidado de casos cuando la declaración como:

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|
+---+---+---+------+

La legibilidad de la lógica anterior con «de otra manera» declaración es poco desordenado si anidada cuando los estados de cuentas va más allá.

¿Hay alguna manera mejor de la implementación de anidado de casos cuando los enunciados en la Chispa de la DataFrames?

InformationsquelleAutor RaAm | 2017-10-09

2 Comentarios

  1. 16

    No hay que anidan aquí, por lo tanto no hay necesidad de otherwise. Todo lo que necesitas es encadenado when:

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

    ELSE NULL es implícita, de modo que usted puede omitir completamente.

    Patrón de uso, es más aplicable para folding a través de una estructura de datos:

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

    donde whenotherwise, naturalmente, sigue la recursividad patrón y null proporciona el caso base.

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

    Por favor, tenga en cuenta, que es imposible llegar a «N» resultado, con esta cadena de condiciones. Si tc es igual a «a» va a ser capturado por la cláusula primera. Si no es así, se producirá un error de satisfacer tanto los predicados y de forma predeterminada NULL. Usted debe más bien:

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

    Por una lógica más compleja, yo prefiero usar Udf para una mejor legibilidad:

    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
    • pero se debe mencionar que la udf podría tener penalización de rendimiento, ya que podría evitar que los filtros de pushdown. este no es siempre el caso, por supuesto, pero es una buena práctica para pegarse a la chispa de funciones nativas tanto como sea posible.

Dejar respuesta

Please enter your comment!
Please enter your name here