当传递“结构”函数的输出时,为什么将火花UDF定义为“行”工作?

时间:2019-07-16 04:55:59

标签: scala apache-spark struct user-defined-functions

我最近遇到了一个工作正常的Spark UDF示例,这让我感到困惑,为什么它实际上可以工作。下面的示例向udf传递数据帧中所有列的结构(只有一个列-数字ID),并且函数为传递的每一行计算所有为空的列的计数。代码是:

  val df = spark.sparkContext.parallelize(List(1,2)).toDF("id")
  spark.
    udf.
    register(
      "nullfinder",
      (r:org.apache.spark.sql.Row) => {
        (0 until r.length).filter(x => !r.isNullAt(x)).sum
      }
    )

  df.selectExpr("nullfinder(struct(*))").show()

输出为:

    +------------------------------------+
    |UDF:nullfinder(named_struct(id, id))|
    +------------------------------------+
    |                               0    |
    |                               0    |
    +------------------------------------+

struct函数的输出(来自org.apache.spark.sql.functions)是一列:

 def struct(cols: Column*): Column 

而Column是仅扩展Logging的案例类。

class Column(val expr: Expression) extends Logging { ....

另一方面,行仅扩展可序列化:

trait Row extends Serializable  { ....

因此,此示例非常有用。.似乎是一种有用的技术。但是我很好奇 为什么struct(*)(这是Column)的结果可以传递到想要org.apache.spark.sql.Row(这是 not Column的超类型)的UDF。 / p>

我已经看到其他S.O.中引用的这项技术。答案(例如,在这里: Using Spark UDFs with struct sequences) 该文章中指出的关键点是:要处理“一系列结构,您可以将Seq [Row]传递给UDF”。 这意味着要处理一个结构,您需要定义您的UDF以采用Row(这就是我所做的。)

[,这是另一篇相关文章:  How to pass whole Row to UDF - Spark DataFrame filter]

所以,我认为它应该工作,并且确实有效。 但我仍然想了解为什么没有类型问题会阻止此工作。

谢谢!

0 个答案:

没有答案