【问题标题】:Spark Scala scala.util.control.Exception catching and dropping None in mapSpark Scala scala.util.control.Exception 在地图中捕获和丢弃 None
【发布时间】:2015-02-05 06:17:55
【问题描述】:

我正在 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) 如何处理通过 catch 创建的 Option 类型,而无需先显式过滤掉 None,然后将 .get 函数映射并应用于非 None Option 值?

我尝试应用 .flatMap(identity) 步骤来摆脱 Nones,但得到了预期的:TraversableOnce[?] 异常。

【问题讨论】:

    标签: scala exception-handling apache-spark rdd


    【解决方案1】:

    在 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 获取到驱动程序。

    【讨论】:

    • 好的,经过一番摆弄,我得到了这个解决方案(例如 Array(x,y) 使 x 和 y Any,所以我只是做了 (x, y) 将它们保存为字符串) .但我有一些问题。首先,必须调用 .toDouble 两次似乎有点奇怪——一次是检查它是否是 toDouble-able,一次是实际执行它。其次,对于这种情况, .collect() 效果很好,因为我可以将 RDD 拉入驱动程序的内存中。但是在我实际处理大数据并且无法使用 .collect() 的情况下,我该怎么办?感谢您的帮助!
    • 回复:collect 我知道这很混乱。 RDD 上有两个collect 方法。无参数版本def collect(): Array[T] 触发计算并将所有数据传递给驱动程序。采用部分函数的版本:def collect[U](f: PartialFunction[T, U])(implicit arg0: ClassTag[U]): RDD[U] 等效于集合上的 Scala collect 函数并生成另一个 RDD,因此它仍然与任何其他 RDD 转换一样并行。
    • rd: toDouble (x2) - 我使用它是因为我更喜欢偏函数版本,但实际上它执行了两倍的操作。这是另一种选择:data.flatMap(entry => Try(entry.toDouble).toOption)
    • 为了以后的访问者,我更新了答案
    猜你喜欢
    • 2016-08-09
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    相关资源
    最近更新 更多