转换不兼容的DecimalType与ClassCastException时的Apache Spark Null值

时间:2019-04-15 12:04:52

标签: scala apache-spark casting

投放DecimalType(10,5),例如Apache Spark中的99999.99999DecimalType( 5,4)默默返回null

是否可以更改此行为,并在这种情况下允许Spark引发异常(例如某些CastException)并导致作业失败,而不是静默返回null

2 个答案:

答案 0 :(得分:0)

根据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。 因此,也许您可​​以尝试检查强制转换列中的null值,并创建逻辑失败(如果有的话)?

答案 1 :(得分:0)

正如我在上面的评论中提到的那样,您可以尝试使用UserDefinedFunction实现所需的功能。我目前正面临同样的问题,但是设法使用UDF解决了我的问题。我面临的问题是我想尝试将列强制转换为DoubleType,但是我不知道类型是什么,并且我不会在解析失败时使应用程序失败,所以请不要像您所说的那样静默'null'关于。

在下面的代码中,您可以看到我写了一个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.