Spark 1.6迁移至2.2时同名UDF注册问题咨询
我之前帮团队处理过Spark 1.6到2.x迁移时的UDF命名冲突问题,刚好和你的场景对上,给你梳理下可行的解决方案:
问题根源先理清楚
在Spark 1.6里,SQLContext和HiveContext的函数注册空间是相对隔离的,所以你能同时注册两个同名的foo(一个Spark SQL的UDF2、一个Hive的GenericUDTF)而不冲突。但到了Spark 2.2,SparkSession统一了所有上下文,函数注册空间合并了,同名UDF就会互相覆盖或者注册失败,这就是你遇到问题的核心原因。
解决方案1:重命名其中一个UDF(最推荐)
这是最直接省心的办法,从根源上消除冲突:
- 对于Spark SQL的UDF,修改注册代码,给它换个独特的名字:
// Spark 2.x用SparkSession代替旧的SQLContext sparkSession.udf().register("foo_spark", new YourUDF2Impl(), DataTypes.StringType); - 对于Hive的GenericUDTF,修改注册SQL的函数名:
sparkSession.sql("CREATE TEMPORARY FUNCTION foo_hive AS 'com.your.package.YourGenericUDTF'");
之后在查询里分别用foo_spark和foo_hive调用对应的函数就行,完全不会冲突。
解决方案2:利用函数空间隔离(不想改名字时用)
如果因为业务原因不能改名字,可以利用Spark 2.x的函数查找规则来区分:
- Spark SQL的UDF属于Spark内置函数空间,Hive UDTF属于Hive的元数据函数空间。默认情况下Spark会优先调用自己注册的UDF,如果你想调用Hive的那个,用全限定名指定:
这里的SELECT default.foo(your_column) FROM your_table;default是Hive的默认数据库,如果你UDTF注册在其他库,换成对应的库名就行。 - 也可以通过配置调整函数优先级,但不推荐(可能影响其他函数):
在初始化SparkSession时添加这个配置,让Spark优先使用Hive的UDF:
注意这个配置会让所有Hive UDF优先于Spark原生UDF,要根据你的业务场景权衡。SparkSession spark = SparkSession.builder() .enableHiveSupport() .config("spark.sql.hive.convertMetastoreUDF", false) .getOrCreate();
额外注意点:适配Spark 2.x的UDTF注册规范
Spark 2.x注册Hive UDTF时,建议使用CREATE TEMPORARY FUNCTION语句(加上TEMPORARY),避免永久修改Hive元数据。另外,Spark 2.2对应的Hive版本是1.2.x,要检查你的GenericUDTF实现是否兼容这个版本,比如一些旧的Hive API可能已经被废弃,需要调整代码适配。
内容的提问来源于stack exchange,提问作者Lunna
相关产品推荐
相关产品推荐

