Spark 2.1:callUDF字符串参数支持问题及更优方案问询
嘿,我来帮你捋捋这个问题——其实你完全不用局限于selectExpr或spark.sql,有两个更优雅、类型更安全的方案可以解决这个问题:
方案1:用callUDF结合lit()传递字符串常量
你之前觉得callUDF只支持字段参数,其实是因为它要求所有参数都是Column类型,普通字符串不属于Column范畴。只要用lit()把你的字符串常量包装成Column类型,就能直接传给callUDF了,这样既能保留DataFrame API的类型安全,又不用写SQL字符串:
import org.apache.spark.sql.functions.{callUDF, lit, col} data.select( col("id"), callUDF("get_from_map", col("map"), lit("attr")).alias("attr_value") ).show(15)
方案2:直接定义Column类型的UDF(最推荐)
如果你的UDF是用Scala编写的,其实完全不需要注册到SQL上下文,直接把它包装成Column类型的函数就行。这种方式在编译期就能做类型检查,还能避免SQL字符串的拼写错误,是最优雅的实现方式:
import org.apache.spark.sql.functions.{udf, col} // 直接定义为Column函数,无需注册到SQLContext val get_from_map_udf = udf((map: Map[String, String], att: String) => map.getOrElse(att, "")) // 调用时直接传字段和lit包装的常量 data.select( col("id"), get_from_map_udf(col("map"), lit("attr")).alias("attr_value") ).show(15)
总结对比
- 方案2是最优解:类型安全、编译期检查、完全基于DataFrame API,没有SQL字符串的冗余
- 方案1适合已经注册了SQL UDF,不想重新定义的场景
selectExpr和spark.sql更多是兼容SQL习惯的方案,类型安全和可读性都不如上面两种
内容的提问来源于stack exchange,提问作者Maayan
相关产品推荐
相关产品推荐

