java.lang.NumberFormatException:对于输入字符串:表上的select count(*)上的“nan”

时间:2016-01-23 03:51:21

标签: apache-spark apache-spark-sql

case class Varnish(ID: String, varnish_latency: Float)


val seq = sc.sequenceFile[LongWritable, BytesWritable](logfile_path)
val usableRDD = seq.map({case (_, v : BytesWritable) => Text.decode(v.getBytes)})
                   .map(_.split(" "))
                   .map(p => Varnish(p(11), p(8).toFloat))
                   .toDF()
usableRDD.registerTempTable("Varnish")
sqlContext.sql("SELECT * from Varnish LIMIT 5").collect().foreach(println) // works fine
val countResult = sqlContext.sql("SELECT COUNT(*) FROM Varnish").collect() // throws Err
val cnt2 = countResult.head.getLong(0)
  

16/01/23 02:56:18 sparkDriver-akka.actor.default-dispatcher-20 INFO RemoteActorRefProvider $ RemotingTerminator:关闭远程守护进程。
  16/01/23 02:56:18 Thread-3 INFO ApplicationMaster:取消注册带有FAILED的ApplicationMaster(诊断消息:用户类引发异常:org.apache.spark.SparkException:由于阶段失败导致作业中止:阶段1.0中的任务57失败4次,最近的失败:
  阶段1.0中失去的任务57.3(TID 89,10.1.201.14):java.lang.NumberFormatException:对于输入字符串:“nan”
      在sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1250)

1 个答案:

答案 0 :(得分:3)

异常似乎是不言自明的。您传递的某些值包含nan字符串,该字符串不会被解释为有效的Float表示形式:

scala> "nan".toFloat
java.lang.NumberFormatException: For input string: "nan"
...

只要数据不是来自已经过验证的源(如RDBMS或Parquet文件),您就不应该盲目相信它具有正确的格式。您可以使用选项修改代码以正确处理此案例和其他格式错误的条目:

import scala.util.Try

case class Varnish(ID: String, varnish_latency: Option[Float])

...
  .map(p => Varnish(p(11), Try(p(8).toFloat).toOption))

删除case类并使用SQL处理它:

...
  .map(p => Varnish(p(11), p(8)))
  .toDF("ID", "varnish_latency")
  .withColumn("varnish_latency", $"varnish_latency".cast("double"))

或在致电.toFloat并删除格式错误的条目之前进行预验证。

前两个选项会将Nones转换为nulls。由于它在语义上不精确(原始非数字与缺失值)并导致信息丢失,因此您可能更愿意明确处理“nan”情况。例如,可以通过在调用"nan"或模式匹配之前将"NaN"替换为toFloat(正确的表示形式)来完成此操作:

p(8) match {
  case "nan" => Float.NaN
  case s => s.toFloat
}