我在Scala中定义了一个UDF,其默认参数值如下:
package myUDFs
import org.apache.spark.sql.api.java.UDF3
class my_udf extends UDF3[Int, Int, Int, Int] {
override def call(a: Int, b: Int, c: Int = 6): Int = {
c*(a + b)
}
}
然后我用build clean assembly
适当地构建它(可以根据需要提供更多构建细节),并提取jar myUDFs-assembly-0.1.1.jar
并将其包含在我的Python Spark配置中:
from pyspark.conf import SparkConf
from pyspark.sql import SparkSession
from pyspark.sql.types import IntType
spark_conf = SparkConf().setAll([
('spark.jars', 'myUDFs-assembly-0.1.1.jar')
])
spark = SparkSession.builder \
.appName('my_app') \
.config(conf = spark_conf) \
.enableHiveSupport() \
.getOrCreate()
spark.udf.registerJavaFunction(
"my_udf", "myUDFs.my_udf", IntType()
)
但是,当我尝试使用默认值时,我被拒绝了:
spark.sql('select my_udf(1, 2)').collect()
AnalysisException:'函数my_udf的参数数量无效。预期:3;发现:2;行x pos y'
难道没有这样的默认值的UDF吗?输出应为6*(1+2) = 18
。
答案 0 :(得分:1)
仅查看调用链,就没有机会在此处识别默认参数。
registerJavaFunction
invokes its JVM UDFRegistration.registerJava
。registerJava
invokes matching register
implementation。对于UDF3
,looks like this,
* Register a deterministic Java UDF3 instance as user-defined function (UDF).
* @since 1.3.0
*/
def register(name: String, f: UDF3[_, _, _, _], returnType: DataType): Unit = {
val func = f.asInstanceOf[UDF3[Any, Any, Any, Any]].call(_: Any, _: Any, _: Any)
def builder(e: Seq[Expression]) = if (e.length == 3) {
ScalaUDF(func, returnType, e, e.map(_ => true), udfName = Some(name))
} else {
throw new AnalysisException("Invalid number of arguments for function " + name +
". Expected: 3; Found: " + e.length)
}
functionRegistry.createOrReplaceTempFunction(name, builder)
}
如您所见,builder
仅在实际分派调用之前验证提供的表达式是否与函数的arity
相匹配。
实现一个中间API可能会更好,该API可以处理默认参数并在幕后分发给UDF。但是,这仅适用于DataFrame
API,因此可能无法满足您的需求。
答案 1 :(得分:-2)
在spark sql中调用函数时,仅传递两个参数。尝试传递三个参数
spark.sql('select my_udf(1, 2, 3 )').collect()