这可以通过创建一个动态 sql 字符串然后映射它来完成。您的方法多次读取相同的数据
这里是解决方案。我使用了一个“示例” DataFrame。
scala> val inputDf = Seq((Some("Sam"),None,200),(None,Some(31),30),(Some("John"),Some(25),25),(Some("Harry"),None,100)).toDF("name","age","not_imp_column")
scala> inputDf.show(false)
+-----+----+--------------+
|name |age |not_imp_column|
+-----+----+--------------+
|Sam |null|200 |
|null |31 |30 |
|John |25 |25 |
|Harry|null|100 |
+-----+----+--------------+
我们的 ValidationColumns 是 name 和 age,我们将在其中计算 Null
我们把它们放在一个列表中
scala> val validationColumns = List("name","age")
我们创建一个 SQL 字符串,它将驱动整个计算
scala> val sqlStr = "select " + validationColumns.map(x => "sum(" + x + "_count) AS " + x + "_sum" ).mkString(",") + " from (select " + validationColumns.map(x => "case when " + x + " = '$$' then 1 else 0 end AS " + x + "_count").mkString(",") + " from " +" (select" + validationColumns.map(x => " nvl( " + x +",'$$') as " + x).mkString(",") + " from example_table where " + validationColumns.map(x => x + " is null ").mkString("or ") + " ) layer1 ) layer2 "
它解析为 ==>
"select sum(name_count) AS name_sum,sum(age_count) AS age_sum from (select case when name = '$$' then 1 else 0 end AS name_count,case when age = '$$' then 1 else 0 end AS age_count from (select nvl( name,'$$') as name, nvl( age,'$$') as age from example_table where name is null or age is null ) layer1 ) layer2 "
现在我们为我们的数据框创建一个临时视图
inputDf.createOrReplaceTempView("example_table")
唯一要做的事情就是执行sql并创建一个Map,由
validationColumns zip spark.sql(sqlStr).collect.map(_.toSeq).flatten.toList toMap
和结果
Map(name -> 1, age -> 2) // 显然你可以让它类型安全