如何在解析期间获取无效数据的计数

时间:2016-09-28 18:58:56

标签: scala apache-spark spark-dataframe bigdata

我们使用spark来解析一个大的csv文件,该文件可能包含无效数据。 我们希望将有效数据保存到数据存储中,并返回导入的有效数据量和无效数据量。

我想知道我们如何在火花中做到这一点,阅读数据时的标准方法是什么?

我当前的方法使用Accumulator,但由于Accumulator在spark中的工作方式,它不准确。

// we define case class CSVInputData: all fields are defined as string
val csvInput = spark.read.option("header", "true").csv(csvFile).as[CSVInputData]

val newDS = csvInput
  .flatMap { row =>
    Try {
      val data = new DomainData()
      data.setScore(row.score.trim.toDouble)
      data.setId(UUID.randomUUID().toString())
      data.setDate(Util.parseDate(row.eventTime.trim))
      data.setUpdateDate(new Date())
      data
    } match {
      case Success(map) => Seq(map)
      case _ => {
        errorAcc.add(1)
        Seq()
      }
    }
}

我尝试使用Either,但失败了例外:

  

java.lang.NoClassDefFoundError:没有与带有scala.util.Either [xx.CSVInputData,xx.DomainData]的Serializable的Product对应的Java类

更新

我认为要么不能使用spark 2.0数据集api:

      spark.read.option("header", "true").csv("any.csv").map { row => 
      try {
        Right("")
      } catch {  case e: Throwable => Left(""); }
      }

如果我们改为使用sc(rdd api),它可以工作:

      sc.parallelize('a' to 'z').map { row => 
      try {
        Right("")
      } catch {  case e: Throwable => Left(""); }
      }.collect()

在当前最新的scala http://www.scala-lang.org/api/2.11.x/index.html#scala.util.Either中:要么没有实现Serializable trait

sealed abstract class Either[+A, +B] extends AnyRef

在未来的2.12 http://www.scala-lang.org/api/2.12.x/scala/util/Either.html中,它确实:

sealed abstract class Either[+A, +B] extends Product with Serializable

已更新2并附带解决方法

Spark ETL: Using Either to handle invalid data

的更多信息

由于spark数据集不能与Either一起使用,因此解决方法是调用ds.rdd,然后使用try-left-right捕获有效和无效数据。

   spark.read.option("header", "true").csv("/Users/yyuan/jyuan/1.csv").rdd.map ( { row => 
   try {
     Right("")
   } catch {  case e: Throwable => Left(""); }
   }).collect()

2 个答案:

答案 0 :(得分:1)

您是否考虑过使用Either

val counts = csvInput
      .map { row =>
        try {
          val data = new DomainData()
          data.setScore(row.score.trim.toDouble)
          data.setId(UUID.randomUUID().toString())
          data.setDate(Util.parseDate(row.eventTime.trim))
          data.setUpdateDate(new Date())
          Right(data)
        } catch {
          case e: Throwable => Left(row)
        }
      }
      val failedCount = counts.map(_.left).filter(_.e.isLeft).count()
      val successCount = counts.map(_.right).filter(_.e.isRight).count()

答案 1 :(得分:0)

您是否尝试过Spark DDQ - 这具有您需要的大多数数据质量规则。您甚至可以扩展和自定义它。

链接:https://github.com/FRosner/drunken-data-quality