如何为任意类型的数组创建通用UDF

时间:2018-04-12 13:26:36

标签: scala apache-spark

假设我想制作一个Spark UDF来反转结构数组的排序。结构的具体类型应该无关紧要,所以我尝试了:

val reverseUDF = udf((s:Seq[_]) => s.reverse)

但是这给了

java.lang.UnsupportedOperationException: Schema for type Any is not supported

我还尝试使用泛型方法和强制类型泛型类型参数作为Product的子类型:

def reverse[T <: Product](s:Seq[T]) = {
  s.reverse
}

val reverseUDF = udf(reverse _)

这给出了:

scala.MatchError: Nothing (of class scala.reflect.internal.Types$TypeRef$$anon$6)

这甚至可能吗?

1 个答案:

答案 0 :(得分:2)

不是。 Spark必须知道返回输出类型,并且无法使用SQL表达式来确定它。您必须为要使用的每种类型定义特定的udf,例如:

udf(reverse[(String, Int)] _)
udf(reverse[(String, Long, String)] _)

等等。但是在实践中这些都没有用,因为你永远不会在你的udf中看到Product类型。结构类型始终编码为Row - Spark Sql UDF with complex input parameter

如果您使用Spark 2.3,您可以将任意reverse表示为:

import org.apache.spark.sql.Row
import org.apache.spark.sql.types.DataType

def reverse(schema: DataType) = udf(
  (xs: Seq[Row]) => xs.map(x => Row.fromSeq(x.toSeq.reverse)),
  schema
)

但您必须为每个实例提供架构: