我正在scala中编写Spark应用程序并希望处理脏输入文件。
// CSV file
val raw_data = sc.textFile(...)
val clean_data = raw_data.map(_.split(delimiter))
.map( r => (r(0), r(1).toDouble)
当r(1)不是数字时,将抛出NumberFormatException。这发生在丑陋的输入数据中的少量行上。
我终于以一种丑陋的方式完成了我的需要:
import scala.util.control.Exception._
val clean_data = raw_data.map(_.split(delimiter))
.map( r => (r(0),
catching(classOf[NumberFormatException]).opt(r(1).toDouble))
.filter( r => r._2 != None)
.map( r => (r._1, r._2.get))
这给我留下两个问题。
1)在地图中简单地删除格式错误的行的最佳方法是什么?
2)如何处理通过捕获创建的Option类型,而无需先显式过滤掉None,然后在非None Option值上映射和应用.get函数?
我尝试应用.flatMap(身份)步骤来摆脱Nones,但得到了预期:TraversableOnce [?]异常。
答案 0 :(得分:4)
在Spark中collect(pf:PartialFunction)
是scala集合collect
的双胞胎兄弟,它正是为了这个目的而存在的:保留集合函数中定义的集合元素。
val rawData = sc.textFile(...)
val cleanData = rawData.map(_.split(Delimiter))
.collect{ case Array(x,y) if (Try(y.toDouble).isSuccess) (x,y.toDouble) }
另一个不评估.toDouble
两次的选项是使用flatMap:
val cleanData = rawData.map(_.split(Delimiter))
.flatMap(entry => Try(entry.toDouble).toOption)
注意:在Spark中有一点令人困惑的是,有一个无参数collect
方法,用于将数据从RDD传送到驱动程序。