【发布时间】:2019-12-16 08:43:19
【问题描述】:
我需要散列 spark 数据帧的特定列。有些列具有特定的数据类型,它们基本上是标准 spark 的 DataType 类的扩展。问题是由于某种原因,在 when 情况下,某些条件无法按预期工作。
作为哈希表,我有一张地图。我们称之为 tableConfig:
val tableConfig = Map("a" -> "KEEP", "b" -> "HASH", "c" -> "KEEP", "d" -> "HASH", "e" -> "KEEP")
盐变量用于与列连接:
val salt = "abc"
散列函数如下所示:
def hashColumns(tableConfig: Map[String, String], salt: String, df: DataFrame): DataFrame = {
val removedColumns = tableConfig.filter(_._2 == "REMOVE").keys.toList
val hashedColumns = tableConfig.filter(_._2 == "HASH").keys.toList
val cleanedDF = df.drop(removedColumns: _ *)
val colTypes = cleanedDF.dtypes.toMap
def typeFromString(s: String): DataType = s match {
case "StringType" => StringType
case "BooleanType" => BooleanType
case "IntegerType" => IntegerType
case "DateType" => DateType
case "ShortType" => ShortType
case "DecimalType(15,7)" => DecimalType(15,7)
case "DecimalType(18,2)" => DecimalType(18,2)
case "DecimalType(11,7)" => DecimalType(11,7)
case "DecimalType(17,2)" => DecimalType(17,2)
case "DecimalType(38,2)" => DecimalType(38,2)
case _ => throw new TypeNotPresentException(
"Please check types in the dataframe. The following column type is missing: ".concat(s), null
)
}
val getType = colTypes.map{case (k, _) => (k, typeFromString(colTypes(k)))}
val hashedDF = cleanedDF.columns.foldLeft(cleanedDF) {
(memoDF, colName) =>
memoDF.withColumn(
colName,
when(col(colName).isin(hashedColumns: _*) && col(colName).isNull, null).
when(col(colName).isin(hashedColumns: _*) && col(colName).isNotNull,
sha2(concat(col(colName), lit(salt)), 256)).otherwise(col(colName)
)
)
}
hashedDF
}
我收到有关特定列的错误。即错误如下:
org.apache.spark.sql.AnalysisException: 由于数据类型不匹配,无法解析 '(
cIN ('a', 'b', 'd', 'e'))':参数必须相同类型但为:布尔值!=字符串;;
列名已更改。
我的搜索没有给出任何明确的解释为什么 isin 或 isNull 函数不能按预期工作。此外,我遵循特定的实现方式,并希望避免以下方法:
1) 没有 UDF。它们对我来说很痛苦。
2) 在 spark 数据框列上没有 for 循环。数据可能包含超过十亿个样本,这在性能方面会令人头疼。
【问题讨论】:
-
正如错误所说,
columns和 hashedColumns 之间似乎不匹配。但是,在此之前您必须修复您的条件,因为col(colName)不能为空并且同时具有以下值之一:['a', 'b', 'c', etc],所以这个col(colName).isin(hashedColumns: _*) && col(colName).isNull永远不会为真。而不是isin,您可能需要使用array_contains -
除了@AlexandrosBiratsis 的评论之外,您还应该根据它们的 DataType 将一些列转换为它们的字符串表示形式(尝试使用您的
getType函数) -
@AlexandrosBiratsis 谢谢!我会检查。但我不确定是否可以将 array_contains 表达式与布尔条件一起使用。
-
@baitmbarek 不幸的是,强制转换没有帮助,只是在函数中留下了帮助代码。
-
你不应该简单地转换你的列,而是将它们转换为一些字符串 representation
标签: scala performance apache-spark