如何使用列和聚合函数的映射为agg中的第一个函数设置ignoreNulls标志?

时间:2017-07-14 19:56:21

标签: scala apache-spark apache-spark-sql apache-spark-2.0

我有大约20-25个来自conf文件的列列表,并且必须聚合第一个Notnull值。我尝试使用函数传递列表和agg expr来读取conf文件。 我能够获得第一个功能,但无法找到如何首先指定ignoreNull值为真。

我尝试的代码是

def groupAndAggregate(df: DataFrame,  cols: List[String] , aggregateFun: Map[String, String]): DataFrame = {
    df.groupBy(cols.head, cols.tail: _*).agg(aggregateFun)
}

val df = sc.parallelize(Seq(
  (0,  null, "1"),
  (1, "2", "2"),
  (0, "3", "3"),
  (0, "4", "4"),
  (1, "5", "5"),
  (1, "6", "6"),
  (1, "7", "7")
)).toDF("grp", "col1", "col2")


//first
groupAndAggregate(df,  List("grp"), Map("col1"-> "first", "col2"-> "COUNT") ).show()

+---+-----------+-----------+
|grp|first(col1)|count(col2)|
+---+-----------+-----------+
|  1|          2|          4|
|  0|           |          3|
+---+-----------+-----------+

我需要得到3作为结果而不是null。 我使用的是Spark 2.1.0和Scala 2.11

编辑1:

如果我使用以下功能

import org.apache.spark.sql.functions.{first,count}
df.groupBy("grp").agg(first(df("col1"), ignoreNulls = true), count("col2")).show()

我得到了我想要的结果。我们可以在地图中传递ignoreNulls true作为第一个函数吗?

2 个答案:

答案 0 :(得分:1)

我已经能够通过创建列列表并将其传递给groupBy的agg函数来实现此目的。早期的方法有一个问题,我无法命名列,因为agg函数没有返回输出DF中列的顺序,我已经重命名列表中的列。

     import org.apache.spark.sql.functions._

     def groupAndAggregate(df: DataFrame): DataFrame = {
        val list: ListBuffer[Column] = new ListBuffer[Column]()
        try {

          val columnFound = getAggColumns(df) // function to return a Map[String, String]

          val agg_func = columnFound.entrySet().toList.
            foreach(field =>
              list += first(df(columnFound.getOrDefault(field.getKey, "")),ignoreNulls = true).as(field.getKey)
            )

          list += sum(df("col1")).as("watch_time")
          list += count("*").as("frequency")

          val groupColumns = getGroupColumns(df) // function to return a List[String]

          val output = df.groupBy(groupColumns.head, groupColumns.tail: _*).agg(
            list.head, list.tail: _*
          )

          output

        } catch {
          case e: Exception => {
            e.printStackTrace()}
            null
        }
      }

答案 1 :(得分:0)

我认为您应该在聚合之前使用na运算符和drop所有null

  

na:DataFrameNaFunctions 返回用于处理缺失数据的DataFrameNaFunctions。

     

drop(cols:Array [String]):DataFrame 返回一个新的DataFrame,它删除包含指定列中任何null或NaN值的行。

然后代码如下:

df.na.drop("col1").groupBy(...).agg(first("col1"))

这会影响count,因此您必须单独执行count