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)
答案 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
}