Hive Server 2 / Beeline 在 HBase 表上的 Hive 上不返回具有 INNER JOIN 的行

Posted

技术标签:

【中文标题】Hive Server 2 / Beeline 在 HBase 表上的 Hive 上不返回具有 INNER JOIN 的行【英文标题】:Hive Server 2 / Beeline returns no rows with an INNER JOIN on a Hive on HBase table 【发布时间】:2016-05-23 21:46:07 【问题描述】:

TL;DR 我可以在 Hive (Hive Server 1) 命令行中对 HBase 表使用 INNER JOIN 执行 Hive 查询并返回正确的行。但是,直线 (Hive Server 2) 命令行上的相同查询不返回任何行。我可以在 HDFS 表上的常规 Hive 上进行 INNER JOIN 罚款。

我已经在以下 MapR 环境中复制了它:

MapR version: 4.0.1.27334.GA -- Hive version: hive-0.13
MapR version: 5.1.0.37549.GA -- Hive version: hive-1.2.0

我创建了两个 HBase 表并像这样填充它们(请注意,在 MapR 中,我们使用分区作为基本名称。如果您想在非 MapR 环境中复制它,请删除 /app/my_partition/ 部分):

create '/app/my_partition/HiveParent', 'f'
create '/app/my_partition/HiveChild', 'f'

put '/app/my_partition/HiveParent', 'foo|a|', 'f:foo', 'a'
put '/app/my_partition/HiveParent', 'foo|b|', 'f:foo', 'b'

put '/app/my_partition/HiveChild', 'foo|a|1|', 'f:foo', 'a'
put '/app/my_partition/HiveChild', 'foo|a|1|', 'f:bar', '1'
put '/app/my_partition/HiveChild', 'foo|a|2|', 'f:foo', 'a'
put '/app/my_partition/HiveChild', 'foo|a|2|', 'f:bar', '2'

put '/app/my_partition/HiveChild', 'foo|b|1|', 'f:foo', 'b'
put '/app/my_partition/HiveChild', 'foo|b|1|', 'f:bar', '1'
put '/app/my_partition/HiveChild', 'foo|b|2|', 'f:foo', 'b'
put '/app/my_partition/HiveChild', 'foo|b|2|', 'f:bar', '2'

我在 hive shell 中创建了 Hive on HBase 表,如下所示:

CREATE EXTERNAL TABLE HiveParent(rk string, foo string)
ROW FORMAT SERDE
  'org.apache.hadoop.hive.hbase.HBaseSerDe'
STORED BY
  'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
  'serialization.format'='1',
  'hbase.columns.mapping'='f:foo'
) TBLPROPERTIES (
  'hbase.table.name'='/app/my_partition/HiveParent'
);

CREATE EXTERNAL TABLE HiveChild(rk string, foo string, bar string)
ROW FORMAT SERDE
  'org.apache.hadoop.hive.hbase.HBaseSerDe'
STORED BY
  'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
  'serialization.format'='1',
  'hbase.columns.mapping'='f:foo,f:bar'
) TBLPROPERTIES (
  'hbase.table.name'='/app/my_partition/HiveChild'
);

以下所有查询在 Hive (Hive Server 1) 和 Beeline (Hive Server 2) 中都能成功运行:

SELECT * FROM HiveParent;
SELECT foo FROM HiveParent;
SELECT foo FROM HiveParent WHERE foo IN ('a', 'b');
SELECT * FROM HiveChild;
SELECT foo, bar FROM HiveChild;
SELECT foo, bar FROM HiveChild WHERE foo IN ('a', 'b'); 

这些查询仅返回 Hive(Hive 服务器 1)中的行。但是,它们在 Beeline (Hive Server 2) 中返回 0 行:

SELECT * FROM HiveParent INNER JOIN HiveChild ON (HiveParent.foo = HiveChild.foo);

SELECT * FROM HiveParent, HiveChild WHERE HiveParent.foo = HiveChild.foo;

SELECT * FROM HiveChild WHERE HiveChild.foo IN (SELECT HiveParent.foo FROM HiveParent); 

编辑:我已将此问题交叉发布到 MapR 的问答网站,因为这并没有引起任何关注。如果有答案,我会在这里发布答案。

【问题讨论】:

【参考方案1】:

这不是一个合适的解决方案,但它有效。

set hive.auto.convert.join = false

hive.auto.convert.join 是做什么的?

如果 hive.auto.convert.join 设置为 true,优化器不仅会将连接转换为 mapjoin,还会尽可能地合并 MJ* 模式

因此,默认情况下,hive 会尝试将连接转换为 map-side joins。 Map-side join 是将两个表中较小的一个完全加载到映射器内存中并且效率更高。通过将hive.auto.convert.join 设置为false,我们将禁用map-side joins 并强制所有joins 为reduce-side join,这样效率低得多。

【讨论】:

【参考方案2】:

我们偶然发现了这个解决方案,但它可能值得研究。在一个环境中,beeline 给出了OutOfMemory 错误并挂起。系统管理员增加了分配给 HS2 的内存,之后 INNER JOIN 工作正常。然而,这令人不安,因为 Beeline 没有抛出任何错误,只是没有返回任何行。

将 MapR5.1/Hive-1.2 环境的内存从 4GB 增加到 8GB 有效。但是,在 MapR4.0.1/Hive-0.13 环境中,这不起作用。

hive-env.sh:

export HADOOP_HEAPSIZE=8000

【讨论】:

以上是关于Hive Server 2 / Beeline 在 HBase 表上的 Hive 上不返回具有 INNER JOIN 的行的主要内容,如果未能解决你的问题,请参考以下文章

hive的几种连接方式

Linux下启动hive服务(beeline)

beeline使用小节

hive beeline详解

减少 Beeline Hive CSV 的详细程度

hive beeline使用