根据 Hive 的版本和您的配置,您的问题的答案可能会有所不同。如果您可以共享您的确切查询以及两个表的创建语句以及它们的大小估计,那将会更容易。
为了更好地理解这个问题,让我们看看 Hive 中的“常规”内部连接是如何工作的。
在 MapReduce 中加入 Hive:
这是 Hive 中的内部连接如何编译为 MapReduce 的简化描述。通常,如果您有两个表 t1 和 t2 并带有如下连接查询:
SELECT
t1.key, t1.value, t2.value
FROM
t1
JOIN
t2 (ON t1.key = t2.key);
其中,t1有以下内容:
k_1 v1_1
k_2 v1_2
k_3 v1_3
其中,t2有以下内容:
k_2 v2_2
k_3 v2_3
k_4 v2_4
我们希望连接结果是
k_2 v1_2 v2_2
k_3 v1_3 v2_3
假设表存储在 HDFS 上,它们的内容将被拆分为文件拆分。映射器将文件拆分作为输入,并发出作为表的键列的键和作为表的值列和标志的组合的值(表示记录来自哪个表,即 t1 或 t2) .
对于 t1:
k_1, <v1_1, t1>
k_2, <v1_2, t1>
k_3, <v1_3, t1>
对于 t2:
k_2, <v2_2, t2>
k_3, <v2_3, t2>
k_4, <v2_4, t2>
现在,这些发出的记录经过混洗阶段,其中所有具有相同键的记录被组合在一起并发送到减速器。每个 reduce 操作的上下文是一个键和一个包含与该键对应的所有值的列表。在实践中,一个 reducer 将执行多个 reduce 操作。
在上面的示例中,我们将获得以下分组:
k_1, <<v1_1, t1>>
k_2, <<v1_2, t1>, <v2_2, t2>>
k_3, <<v1_3, t1>, <v2_3, t2>>
k_4, <<v2_4, t2>>
这是减速器中发生的事情。对于值列表中的每个值,如果这些值对应于不同的表,reducer 将执行乘法运算。
对于 k_1,t2 没有任何值,也没有发出任何内容。
对于 k_2,发出值的乘法 - k_2、v1_2、v2_2(因为每个表都有一个值,1x1 = 1)
对于 k_3,会发出值的乘积 - k_3、v1_3、v2_3(因为每个表都有一个值,1x1 = 1)
对于 k_4,t1 没有任何值,也没有发出任何内容。因此,您从内部联接中获得了预期的结果。
好的,那我该怎么办?
您的数据可能存在偏差。换句话说,当reducer获取数据时,某个key对应的value列表很长,导致出错。为了缓解这个问题,您可以尝试增加 JVM 可用的内存。您可以通过设置为hive-site.xml 中mapred.child.java.opts
的值来执行此操作。您可以通过在 Hive shell 中-Xmx512M
执行来查询此参数的当前值。set mapred.child.java.opts;
您可以尝试使用“常规”连接的替代方法,例如地图连接。以上对连接的解释适用于连接发生在减速器中的常规连接。根据您使用的 Hive 版本,Hive 可能会自动将常规连接转换为更快的映射连接(因为连接发生在映射阶段)。要启用优化,请设置hive.auto.convert.join
为true
。此属性是在Hive 0.7中引入的
除了设置hive.auto.convert.join
为true
,您还可以设置hive.optimize.skewjoin
为true
。这将解决 1 中描述的数据问题中的偏差。