hive 大小表mapjoin 遇到udf失效问题

hive 使用mysql hive 使用in语句 udf函数失效_大数据

执行结果有三个重要信息:

  1. /tmp/liangxin/liangxin_20201026173636_ddccc70a-1019-49d4-9cc8-6b072023187a.log
  2. Stage-4
  3. /tmp/liangxin/hive.log

问题分析:

  1. 打开第一个文件发现udf函数没找到,对比执行sql,on dwc_mart.transtring(a.altitem)=dwc_mart.transtring(b.pa_code) 使用了udf

hive 使用mysql hive 使用in语句 udf函数失效_大数据_02

  1. explain 执行语句,找到stage4,发现启动了本地模式,本地模式下进行了mapjoin操作

知因智慧-平台产品部 > 大小表mapjoin问题 > 企业微信截图_16037054575085.png

  1. 打开第三个log,发现 ql.Driver报错

知因智慧-平台产品部 > 大小表mapjoin问题 > 企业微信截图_16037057536924.png

原理分析

下面是mapjoin执行进程图。

左边是小表的执行过程,udf包放在了hdfs上,在本地模式下,不会去hdfs上找udf的jar包,所以启动local task jvm时找不到对应的jar包报错。

知因智慧-平台产品部 > 大小表mapjoin问题 > 企业微信截图_420e50b7-ece3-4ba6-8d95-7dd33fcc80c3.png

  1. 在hive客户端提交上面Sql,在客户端本地启动一个DriverJVM进程,
  2. Driver 进程解析脚本,语法分析,语意分析,读取元数据,生成逻辑执行计划,逻辑优化,最终生成一个物理执行计划。
  3. 接下来执行物理执行计划。对于这个SQL来说,流程如下。
  4. 首先从HDFS下载UDF jar包到 Driver进程中,放在classpath 中。这一步可以可以从日志中看到,创建临时自定义函数。
  5. 因为右侧表是小表,所以生成的物理执行计划是mapjoin ,那么就在客户端本地机器启动一个LocalTask JVM进程,(这一步可以从日志中看到)用来从HDFS读取小表数据到内存中,在内存中转换为HashTable,根据语句,在这里执行自定义函数。
  6. 当Local Task 执行完毕后,Driver 进程负责将classpath 中jar 包、物理执行计划、小表生成的HashTable 提交Yarn 上去执行。
  7. 根据物理执行计划,Yarn上执行的 ApplicationMaster 分配多个Map 节点从HDFS上读取左侧大表数据,同时会将小表的HashTable分发到各个Map节点中,每个节点分配一个小表全量放在内存里。
  8. 然后每个Map节点处理大表的一部分数据,同时与小表进行关联,这一步就是mapjoin,关联的结果输出写入HDFS。
    根据日志,显然是在Local Task这一步出错了,报的错是ClassNotFound,为什么找不到UDF的类呢?所以猜测jar包的加载是在Driver JVM中做的,Local Task中并没有加载jar包,所以找不到类。

解决策略

  1. 避免mapjoin使用udf函数。在join之前处理好对应列。
  2. 关闭mapjoin,设置set hive.auto.convert.join=false;
  3. 在单机模式下,本地加载udf包(待验证)