我们使用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()
答案 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 - 这具有您需要的大多数数据质量规则。您甚至可以扩展和自定义它。