【问题标题】:Apache Spark Null Value when casting incompatible DecimalType vs ClassCastException投射不兼容的 DecimalType 与 ClassCastException 时的 Apache Spark Null 值
【发布时间】:2019-09-05 09:55:39
【问题描述】:

铸造DecimalType(10,5) 例如99999.99999DecimalType(5,4) 在 Apache Spark 中静默返回 null

是否可以改变这种行为并允许 Spark 在这种情况下抛出异常(例如一些 CastException)并使作业失败而不是静默返回 null

【问题讨论】:

  • 你找到干净的解决方案了吗?

标签: scala apache-spark casting


【解决方案1】:

根据 Git 中心文档,https://github.com/apache/spark/blob/3ab96d7acf870e53c9016b0b63d0b328eec23bed/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala#L499

/** * 将给定小数的精度/比例更改为那些设置 在decimalType(如果有)中,* 如果溢出则返回 null 或 就地修改value,如果成功则返回。 * * 注意:这会就地修改value,所以不要在外部调用它 数据。 */

还有另一个线程,表明如果不能强制转换,可能没有直接的方法使代码失败。 Spark: cast decimal without changing nullable property of column。 那么,也许您可​​以尝试检查转换列中的 nullvalue 并创建一个失败的逻辑(如果有)?

【讨论】:

  • 检查空值不是一个可靠的解决方案,因为在该列中可能有其他不是由强制转换引起的空值。除非您在强制转换之前替换所有空值。我建议(就像上面给出的线程中所述)编写自己的 UserDefinedFunction ,然后可以抛出异常。
  • @RubyVerboven 非常适合 Java/Scala。由于 PySpark UDF 很慢,您必须使用 Scala UDF 来处理额外的痛苦
【解决方案2】:

正如我在上面的评论中提到的,您可以尝试使用 UserDefinedFunction 来实现您想要的。我目前面临同样的问题,但设法使用 UDF 解决了我的问题。我面临的问题是我想尝试将一列强制转换为 DoubleType 但我不知道预先的类型,并且我不希望我的应用程序在解析失败时失败,所以不像你说的那样是无声的“空”关于。

在下面的代码中,您可以看到我编写了一个udf,它以struct 作为参数。我将尝试将此结构中的唯一值解析为双精度值。如果这失败了,我会抛出一个异常,导致我的工作失败。

import spark.implicits._

val cast_to_double = udf((number: Row) => {
  try {
    number.get(0) match {
      case s: String => s.toDouble
      case d: Double => d
      case l: Long => l.toDouble
      case i: Int => i.toDouble
      case _ => throw new NumberFormatException
    }
  } catch {
    case _: NumberFormatException => throw new IllegalArgumentException("Can't parse this so called number of yours.")
  }
})

try {
  val intDF = List(1).toDF("something")
  val secondIntDF = intDF.withColumn("something_else", cast_to_double(struct(col("something"))))
  secondIntDF.printSchema()
  secondIntDF.show()

  val stringIntDF = List("1").toDF("something")
  val secondStringIntDF = stringIntDF.withColumn("something_else", cast_to_double(struct(col("something"))))
  secondStringIntDF.printSchema()
  secondStringIntDF.show()

  val stringDF = List("string").toDF("something")
  val secondStringDF = stringDF.withColumn("something_else", cast_to_double(struct(col("something"))))
  secondStringDF.printSchema()
  secondStringDF.show()
} catch {
  case se: SparkException => println(se.getCause.getMessage)
}

输出:

root
 |-- something: integer (nullable = false)
 |-- something_else: double (nullable = false)

+---------+--------------+
|something|something_else|
+---------+--------------+
|        1|           1.0|
+---------+--------------+

root
 |-- something: string (nullable = true)
 |-- something_else: double (nullable = false)

+---------+--------------+
|something|something_else|
+---------+--------------+
|        1|           1.0|
+---------+--------------+

root
 |-- something: string (nullable = true)
 |-- something_else: double (nullable = false)

Can't parse this so called number of yours.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-04
    • 2022-09-22
    • 2020-07-28
    • 2014-03-12
    • 2019-05-10
    • 1970-01-01
    • 2015-11-16
    • 2022-06-14
    相关资源
    最近更新 更多