我创建了一个包含 3 个存储桶的表,并将一些数据加载到其中。
create table testBucket (id int,name String)
partitioned by (region String)
clustered by (id) into 3 buckets;
Run Code Online (Sandbox Code Playgroud)
我也设置了分桶属性。 $set hive.enforce.bucketing=true;
但是当我在 HDFS 中列出表文件时,我可以看到创建了 3 个文件,正如我提到的 3 个存储桶。但是数据仅加载到一个文件中,其余 2 个文件只是空的。所以我很困惑为什么我的数据被加载到唯一的文件中?
那么有人可以解释一下数据分布在分桶中是如何发生的吗?
[test@localhost user]$ hadoop fs -ls /user/hive/warehouse/database2.db/buckettab/region=USA
Found 3 items
-rw-r--r-- 1 user supergroup 38 2016-06-27 08:34 /user/hive/warehouse/database2.db/buckettab/region=USA/000000_0
-rw-r--r-- 1 user supergroup 0 2016-06-27 08:34 /user/hive/warehouse/database2.db/buckettab/region=USA/000001_0
-rw-r--r-- 1 user supergroup 0 2016-06-27 08:34 /user/hive/warehouse/database2.db/buckettab/region=USA/000002_0
Run Code Online (Sandbox Code Playgroud)
分桶是一种将数据均匀分布在多个文件中的方法。创建多个存储桶,然后根据一些逻辑(主要是一些散列算法)将每条记录放入其中一个存储桶中。
Hive 的分桶功能可用于将表/分区数据分布/组织到多个文件中,以便类似的记录存在于同一文件中。在创建 Hive 表时,用户需要提供用于分桶的列以及存储数据的桶数。哪些记录去哪个桶是由用于分桶的列的哈希值决定的。
[Hash(column(s))] MOD [桶数]
不同列类型的哈希值计算方式不同。对于 int 列,哈希值等于 int 的值。对于字符串列,哈希值是使用字符串中存在的每个字符的一些计算来计算的。
每个桶的数据存储在 HDFS 上表目录下的单独 HDFS 文件中。在每个桶内,我们可以通过在创建表时提供 SORT BY 列来定义数据的排列。
让我们看一个例子
使用分桶创建 Hive 表
为了创建分桶表,我们需要使用 CLUSTERED BY 子句来定义分桶的列并提供桶的数量。以下查询使用 ID 列创建一个表 Employee 分桶为 5 个桶。
CREATE TABLE Employee(
ID BIGINT,
NAME STRING,
AGE INT,
SALARY BIGINT,
DEPARTMENT STRING
)
COMMENT 'This is Employee table stored as textfile clustered by id into 5 buckets'
CLUSTERED BY(ID) INTO 5 BUCKETS
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
Run Code Online (Sandbox Code Playgroud)
将数据插入到分桶表中
我们在 Employee_old 表中有以下数据。
0: jdbc:hive2://localhost:10000> select * from employee_old;
+------------------+--------------------+-------------------+----------------------+--------------------------+--+
| employee_old.id | employee_old.name | employee_old.age | employee_old.salary | employee_old.department |
+------------------+--------------------+-------------------+----------------------+--------------------------+--+
| 1 | Sudip | 34 | 62000 | HR |
| 2 | Suresh | 45 | 76000 | FINANCE |
| 3 | Aarti | 25 | 37000 | BIGDATA |
| 4 | Neha | 27 | 39000 | FINANCE |
| 5 | Rajesh | 29 | 59000 | BIGDATA |
| 6 | Suman | 37 | 63000 | HR |
| 7 | Paresh | 42 | 71000 | BIGDATA |
| 8 | Rami | 33 | 56000 | HR |
| 9 | Arpit | 41 | 46000 | HR |
| 10 | Sanjeev | 51 | 99000 | FINANCE |
| 11 | Sanjay | 32 | 67000 | FINANCE |
+------------------+--------------------+-------------------+----------------------+--------------------------+--+
Run Code Online (Sandbox Code Playgroud)
我们将从 Employee_old 表中选择数据并将其插入到我们的分桶表 Employee 中。
我们需要在将数据插入分桶表时将属性 'hive.enforce.bucketing' 设置为 true。这将强制执行分桶,同时将数据插入表中。
0: jdbc:hive2://localhost:10000> 设置 hive.enforce.bucketing=true;
0: jdbc:hive2://localhost:10000> INSERT OVERWRITE TABLE Employee SELECT * from Employee_old;
Run Code Online (Sandbox Code Playgroud)
验证桶中的数据
一旦我们执行 INSERT 查询,我们可以验证在 HDFS 上的 Employee 表目录下创建了 5 个文件。
Name Type
000000_0 file
000001_0 file
000002_0 file
000003_0 file
000004_0 file
Run Code Online (Sandbox Code Playgroud)
每个文件代表一个桶。让我们看看这些文件的内容。
000000_0 的内容
Hash(ID) mod 5 == 0 的所有记录都进入这个文件。
5,Rajesh,29,59000,BIGDATA
10,Sanjeev,51,99000,FINANCE
Run Code Online (Sandbox Code Playgroud)
000001_0 的内容
Hash(ID) mod 5 == 1 的所有记录都进入这个文件。
1,Sudip,34,62000,HR
6,Suman,37,63000,HR
11,Sanjay,32,67000,FINANCE
Run Code Online (Sandbox Code Playgroud)
000002_0 的内容
Hash(ID) mod 5 == 2 的所有记录都进入这个文件。
2,Suresh,45,76000,FINANCE
7,Paresh,42,71000,BIGDATA
Run Code Online (Sandbox Code Playgroud)
000003_0 的内容
Hash(ID) mod 5 == 3 的所有记录都进入这个文件。
3,Aarti,25,37000,BIGDATA
8,Rami,33,56000,HR
Run Code Online (Sandbox Code Playgroud)
000004_0 的内容
Hash(ID) mod 5 == 4 的所有记录都进入这个文件。
4,Neha,27,39000,FINANCE
9,Arpit,41,46000,HR
Run Code Online (Sandbox Code Playgroud)