Hive - 分桶和分区

Hive - Bucketing and Partitioning

我们应该根据什么来缩小是对 Hive 中的一组列使用分区还是分桶?

假设我们有一个庞大的数据集,其中有两列最常被查询 - 所以我明显的选择可能是根据这两列进行分区,但如果这会导致一个巨大的数字在大量目录中创建的小文件,而不是根据这些列对数据进行分区是错误的决定,并且分桶可能是更好的选择。

我们能否定义一种方法来决定我们应该进行分桶还是分区?

分区:

分区是 decomposing/dividing 您根据某些条件输入的数据,例如:此处的日期、国家/地区。

创建 TABLE 日志(ts BIGINT,行 STRING) PARTITIONED BY (dt STRING, country STRING);

加载数据本地输入路径'input/hive/partitions/file1' INTO TABLE logs PARTITION (dt='2012-01-01', country='GB');

加载数据后在仓库中创建的文件如下:

/user/hive/warehouse/logs/dt=2012-01-01/国家=GB/file1/

/user/hive/warehouse/logs/dt=2012-01-01/国家=GB/file2/

/user/hive/warehouse/logs/dt=2012-01-01/国家=US/file3/

/user/hive/warehouse/logs/dt=2012-01-02/国家=GB/file4/

/user/hive/warehouse/logs/dt=2012-01-02/国家=US/file5/

/user/hive/warehouse/logs/dt=2012-01-02/国家=US/file6

SELECT ts, dt, 线 来自日志 WHERE 国家='GB';

此查询将只扫描文件 1、文件 2 和文件 4。

分桶:

分桶进一步 Decomposing/dividing 您的输入数据基于其他一些条件。

我们可能想要将 table(或分区)组织到存储桶中的原因有两个。

首先是启用更高效的查询。 Bucketing 在 table 上强加了额外的结构,Hive 在执行某些查询时可以利用它。特别是,在相同列(包括连接列)上分桶的两个 table 的连接可以有效地实现为映射端连接。

存储 a table 的第二个原因是提高采样效率。在处理大型数据集时,在开发或优化数据集的过程中尝试对数据集的一小部分进行查询非常方便。

让我们看看如何告诉 Hive 一个 table 应该被分桶。我们使用 CLUSTERED BY 子句来指定要分桶的列和分桶的数量:

创建 TABLE 学生 (rollNo INT, name STRING) CLUSTERED BY (id) INTO 4 BUCKETS;

SELECT * 来自学生 TABLESAMPLE(BUCKET 1 OUT OF 4 ON rand());

分桶和分区并不排斥,可以同时使用。

根据我相当长的蜂巢经验,我的简短回答是 "you should ALWAYS use partitioning, and sometimes you may want to bucket too"。

如果您有一个大 table,分区有助于减少您查询的数据量。分区通常表示为 HDFS 上的目录。一个常见的用法是按 year/month/day 分区,因为大多数人按日期查询。 唯一的缺点是您不应该对具有大基数的列进行分区。 基数是大数据中的一个基本概念,它是一列可能具有的值的数量。例如 'US state' 具有低基数(大约 50),而例如 'ip_number' 具有大基数(2^32 可能的数字)。 如果在高基数的字段上分区,hive 将在 HDFS 中创建大量目录,这并不好(namenode 上的额外内存负载)。

分桶很有用,但在将数据插入 table 时也必须遵守纪律。 Hive 不会检查您插入的数据是否按照预期的方式分桶。 分桶 table 必须执行 CLUSTER BY,这可能会在您的处理中增加一个额外的步骤。 但是如果你做很多连接,如果 both tables 以相同的方式存储(在相同的字段和相同数量的存储桶上),它们可以大大加快。另外,一旦你决定了桶的数量,你就不能轻易改变它。