最近,结合我使用Spark开发模块化、基于元数据的引入引擎,我们进行了有关数据验证的讨论。数据验证是数据引入的一个自然的下一步,这就是为什么我们来到这个主题。
您可能想知道,”数据验证有什么特别?是因为火花吗?本文的部分原因是 Spark,但更重要的是,它展示了 Spark 的强大功能,也说明了有不止一种方法可用于实现我们的目标的原则。
手头的任务非常简单 , 我们希望创建一个灵活且可重用的类库,使数据验证任务(在 Spark DataFrame 上)变得轻而易举。在本文中,我将介绍用于数据验证的一些技术/习惯。特别是,我使用的是 null 检查(是列的”null”的内容)。为了保持简单,我将假定要验证的数据已加载到名为”df”的Spark DataFrame中。
方法一:筛选
执行验证的最简单方法之一是筛选出无效记录。执行此操作的方法为 val newDF = df.filter(col("name").isNull)
。
此技术的一个变体是:
val newDF = df.filter(col("name").isNull).withColumn("nameIsNull", lit(true))
此技术是过度杀伤的 , 主要是因为 中的所有 newDF
记录都是名称列不为空的记录。因此,添加具有”true”值的新列是完全不必要的,因为所有行都将具有此列的值为”true”。
方法二:何时/否则
第二种技术是使用”when”和”否则”构造。
val newDF = df.withColumn("nameIsNull", when(col("name") === null ||
col("name").equals(""), true).otherwise(false))
此方法添加新列,指示名称列的 null 比较结果。在此技术之后,新列中的单元格将同时包含”true”和”false”,具体取决于名称列的内容。
方法三:使用Expr
另一种技术是使用”expr”功能。
val newDF = df.withColumn("nameIsNull", expr("case when name == null then true else false end"))
方法四:过度杀戮
现在,看看这个技术。
var dfFinal: DataFrame = _
var dfTrue = df.filter(col("name").isNull).withColumn("nameIsNull", lit(true))
var dfFalse = df.filter(!col("name").isNull).withColumn("nameIsNull", lit(false))
if ( dfTrue != null ) {
dfFinal = dfTrue.union(dfFalse)
} else {
dfFinal = dfFalse
}
虽然有效,但这种方法显然是一种过度的杀伤。与之前的方法相比,它不仅更加精细,而且还在做双倍的工作。它扫描 DataFrame 两次 – 一次用于评估”真实”条件,一次再次评估”假”条件这些技术不仅说明了Spark的灵活性,而且证明了我们可以通过多种方式达到同一最终目标。
显然,有一些权衡,但有时,我们可能想要选择一种易于理解和维护的方法,而不是仅仅因为 API 提供技术而使用技术。在下一篇文章中,我将介绍如何使用 UF 实现类似目标。