Scala 当udf函数不接受足够大的输入变量时触发数据帧

Scala 当udf函数不接受足够大的输入变量时触发数据帧,scala,apache-spark,dataframe,apache-spark-sql,apache-spark-mllib,Scala,Apache Spark,Dataframe,Apache Spark Sql,Apache Spark Mllib,我正在准备一个带有id和特征向量的数据帧,以便稍后用于进行预测。我在我的数据帧上执行groupBy,在我的groupBy中,我将两列作为列表合并到一个新列中: def mergeFunction(...) // with 14 input variables val myudffunction( mergeFunction ) // Spark doesn't support this df.groupBy("id").agg( collect_list(df(...)) as ...

我正在准备一个带有id和特征向量的数据帧,以便稍后用于进行预测。我在我的数据帧上执行groupBy,在我的groupBy中,我将两列作为列表合并到一个新列中:

def mergeFunction(...) // with 14 input variables

val myudffunction( mergeFunction ) // Spark doesn't support this

df.groupBy("id").agg(
   collect_list(df(...)) as ...
   ... // too many of these (something like 14 of them)
).withColumn("features_labels",
  myudffunction(
     col(...)
     , col(...) )
.select("id", "feature_labels")
这就是我创建特征向量及其标签的方式。到目前为止,它一直在为我工作,但这是我第一次用这种方法得到的特征向量大于数字10,这是Spark中的udf函数最多可以接受的

我不知道我还能怎么解决这个问题?是中udf输入的大小 火花会越来越大,我是不是理解错了,还是 有更好的办法吗


用户定义的函数最多可定义22个参数。仅为最多10个参数定义了
udf
helper。要处理具有大量参数的函数,可以使用
org.apache.spark.sql.UDFRegistration

比如说

val dummy = ((
  x0: Int, x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, 
  x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, 
  x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int) => 1)
必须注册的车辆:

import org.apache.spark.sql.expressions.UserDefinedFunction

val dummyUdf: UserDefinedFunction = spark.udf.register("dummy", dummy)
直接使用

val df = spark.range(1)
val exprs =  (0 to 21).map(_ => lit(1))

df.select(dummyUdf(exprs: _*))
或者通过
callUdf

import org.apache.spark.sql.functions.callUDF

df.select(
  callUDF("dummy", exprs:  _*).alias("dummy")
)
或SQL表达式:

df.selectExpr(s"""dummy(${Seq.fill(22)(1).mkString(",")})""")
您还可以创建
UserDefinedFunction
对象:

import org.apache.spark.sql.expressions.UserDefinedFunction

Seq(1).toDF.select(UserDefinedFunction(dummy, IntegerType, None)(exprs: _*))
实际上,拥有22个参数的函数并不是很有用,除非您想使用Scala反射来生成这些参数,否则会有维护噩梦

我会考虑使用集合(<代码>数组< /COD>,<代码> map < /COD>)或<代码>结构> /代码>作为输入或将其划分为多个模块。例如:

val aLongArray = array((0 to 256).map(_ => lit(1)): _*)

val udfWitharray = udf((xs: Seq[Int]) => 1)

Seq(1).toDF.select(udfWitharray(aLongArray).alias("dummy"))

用户定义的函数最多可定义22个参数。仅为最多10个参数定义了
udf
helper。要处理具有大量参数的函数,可以使用
org.apache.spark.sql.UDFRegistration

比如说

val dummy = ((
  x0: Int, x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, 
  x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, 
  x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int) => 1)
必须注册的车辆:

import org.apache.spark.sql.expressions.UserDefinedFunction

val dummyUdf: UserDefinedFunction = spark.udf.register("dummy", dummy)
直接使用

val df = spark.range(1)
val exprs =  (0 to 21).map(_ => lit(1))

df.select(dummyUdf(exprs: _*))
或者通过
callUdf

import org.apache.spark.sql.functions.callUDF

df.select(
  callUDF("dummy", exprs:  _*).alias("dummy")
)
或SQL表达式:

df.selectExpr(s"""dummy(${Seq.fill(22)(1).mkString(",")})""")
您还可以创建
UserDefinedFunction
对象:

import org.apache.spark.sql.expressions.UserDefinedFunction

Seq(1).toDF.select(UserDefinedFunction(dummy, IntegerType, None)(exprs: _*))
实际上,拥有22个参数的函数并不是很有用,除非您想使用Scala反射来生成这些参数,否则会有维护噩梦

我会考虑使用集合(<代码>数组< /COD>,<代码> map < /COD>)或<代码>结构> /代码>作为输入或将其划分为多个模块。例如:

val aLongArray = array((0 to 256).map(_ => lit(1)): _*)

val udfWitharray = udf((xs: Seq[Int]) => 1)

Seq(1).toDF.select(udfWitharray(aLongArray).alias("dummy"))

只需扩展zero的答案,就可以获得
.withColumn()
函数来处理具有10个以上参数的UDF。只需
spark.udf.register()
函数,然后使用
expr
作为添加列的参数(而不是
udf

例如,类似这样的方法应该有效:

def mergeFunction(...) // with 14 input variables

spark.udf.register("mergeFunction", mergeFunction) // make available in expressions

df.groupBy("id").agg(
   collect_list(df(...)) as ...
   ... // too many of these (something like 14 of them)
).withColumn("features_labels",
  expr("mergeFunction(col1, col2, col3, col4, ...)") ) //pass in the 14 column names
.select("id", "feature_labels")

底层表达式解析器似乎处理10个以上的参数,因此我认为不必通过传递数组来调用函数。另外,如果它们的参数恰好是不同的数据类型,那么数组将不能很好地工作。

仅扩展zero的答案,就可以使用
。withColumn()
函数来处理具有10个以上参数的UDF。只需
spark.udf.register()
函数,然后使用
expr
作为添加列的参数(而不是
udf

例如,类似这样的方法应该有效:

def mergeFunction(...) // with 14 input variables

spark.udf.register("mergeFunction", mergeFunction) // make available in expressions

df.groupBy("id").agg(
   collect_list(df(...)) as ...
   ... // too many of these (something like 14 of them)
).withColumn("features_labels",
  expr("mergeFunction(col1, col2, col3, col4, ...)") ) //pass in the 14 column names
.select("id", "feature_labels")
底层表达式解析器似乎处理10个以上的参数,因此我认为不必通过传递数组来调用函数。而且,如果它们的参数恰好是不同的数据类型,那么数组将不能很好地工作