Hive切换Spark引擎后执行含UDF的SQL时出现类找不到异常
这个问题我之前在迁移Hive执行引擎时也碰到过,核心原因是集群模式下Spark Executor节点无法获取到你通过add jar添加的UDF包——客户端模式下jar在本地Driver所在机器,Executor可能能直接访问到,但集群模式下Executor分布在各个远程节点,默认不会自动同步这个jar。
下面是几个可行的解决方案,按灵活性从高到低排序:
方案1:启动Hive时显式指定UDF jar
在启动Hive客户端的时候,通过--jars参数把UDF jar传递给Spark,这样Spark会自动把jar分发到所有Executor节点:
hive --jars viewfs:///path_to_the_jar/aaa.jar
进入Hive shell后再执行你的set引擎、创建临时函数和查询语句即可。
方案2:在Hive会话中配置Spark的额外类路径
在执行add jar之前,先设置Spark的Driver和Executor额外类路径,确保所有节点都能访问到这个jar(注意viewfs路径必须是集群全局可访问的):
set hive.execution.engine=spark; set spark.driver.extraClassPath=viewfs:///path_to_the_jar/aaa.jar; set spark.executor.extraClassPath=viewfs:///path_to_the_jar/aaa.jar; add jar viewfs:///path_to_the_jar/aaa.jar; create temporary function func_name AS 'com.abc.ClassName'; select func_name(col_a) from table_name limit 100;
方案3:将UDF jar放到Spark全局类路径
如果有集群运维权限,可以把UDF jar复制到每个Spark节点的$SPARK_HOME/jars目录下,然后重启Spark集群。这种方式一劳永逸,但不够灵活,适合常用的UDF包。
方案4:创建永久函数时指定jar路径
如果这个UDF是多个会话都需要用的,建议创建永久函数并直接指定HDFS(或viewfs)上的jar路径,这样Hive会自动管理jar的分发:
create function func_name AS 'com.abc.ClassName' using jar 'viewfs:///path_to_the_jar/aaa.jar';
之后执行查询时就不需要每次add jar了,集群模式下也能正常加载。
补充说明
集群模式下Spark的Driver和Executor是分离的,add jar只是把jar添加到了Driver的类路径,但Executor节点无法感知到这个操作,必须通过Spark的分发机制把jar传递过去——上面的方案都是围绕让Executor能获取到UDF jar来解决的。
内容的提问来源于stack exchange,提问作者KAs

