如何在HIVE中进行数据分发?

时间:2016-06-29 16:14:54

标签: hadoop hive hdfs

我用3个桶创建了一个表,并将一些数据加载到其中。

create table testBucket (id int,name String)        
    partitioned by (region String)
    clustered by (id) into 3 buckets;    

我也设置了bucketing属性。 $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

3 个答案:

答案 0 :(得分:1)

Bucketing是一种在多个文件中均匀分布数据的方法。创建多个存储桶,然后根据某些逻辑(主要是一些散列算法)将每个记录放入其中一个存储桶中。

Hive的Bucketing功能可用于将表/分区数据分发/组织到多个文件中,以便在同一文件中存在类似的记录。在创建Hive表时,用户需要提供用于存储的列以及用于存储数据的存储桶数。哪些记录取决于用于分组的列的哈希值决定哪个桶。

  

[哈希(列(s))] MOD [桶数]

不同列类型的哈希值计算方式不同。对于int列,哈希值等于int的值。对于String列,使用对String中存在的每个字符进行一些计算来计算哈希值。

每个存储桶的数据存储在HDFS上的表目录下的单独HDFS文件中。在每个存储桶中,我们可以通过在创建表时提供​​SORT BY列来定义数据的排列。

让我们看一个例子

使用bucketing

创建Hive表

为了创建一个分段表,我们需要使用CLUSTERED BY子句来定义bucketing的列并提供桶的数量。以下查询创建一个表Employee,使用ID列将其分成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;

将数据插入分段表

我们在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                  |
+------------------+--------------------+-------------------+----------------------+--------------------------+--+

我们将从表Employee_old中选择数据并将其插入到我们的分段表Employee中。

我们需要将数据'hive.enforce.bucketing'设置为true,同时将数据插入到分段表中。这将强制执行分段,同时将数据插入表中。

设置属性

0:jdbc:hive2:// localhost:10000> set hive.enforce.bucketing = true;

将数据插入Bucketed表employee

0: jdbc:hive2://localhost:10000> INSERT OVERWRITE TABLE Employee SELECT * from Employee_old;

验证存储桶中的数据

执行INSERT查询后,我们可以验证在HDFS上的Employee表目录下是否创建了5个文件。

Name        Type
000000_0    file
000001_0    file
000002_0    file
000003_0    file
000004_0    file

每个文件代表一个存储桶。让我们看看这些文件的内容。

内容000000_0

所有带有哈希(ID)mod 5 == 0的记录都会进入此文件。

5,Rajesh,29,59000,BIGDATA
10,Sanjeev,51,99000,FINANCE

内容000001_0

所有带有哈希(ID)mod 5 == 1的记录都会进入此文件。

1,Sudip,34,62000,HR
6,Suman,37,63000,HR
11,Sanjay,32,67000,FINANCE

内容000002_0

所有带有哈希(ID)mod 5 == 2的记录都会进入此文件。

2,Suresh,45,76000,FINANCE
7,Paresh,42,71000,BIGDATA

内容000003_0

所有带有哈希(ID)mod 5 == 3的记录都会进入此文件。

3,Aarti,25,37000,BIGDATA
8,Rami,33,56000,HR

内容000004_0

所有带有哈希(ID)mod 5 == 4的记录都会进入此文件。

4,Neha,27,39000,FINANCE
9,Arpit,41,46000,HR

答案 1 :(得分:0)

我觉得样本数据中的USA分区(region = USA)的所有 ID MOD 3 都相同。

存储桶编号由表达式hash_function(bucketing_column)mod num_buckets确定。 (那里也有一个' 0x7FFFFFFF,但那并不重要)。 hash_function取决于bucketing列的类型。对于int,它很容易,hash_int(i)== i。例如,如果user_id是一个int,并且有10个桶,我们希望所有以0结尾的user_id都在桶1中,所有以1结尾的user_id都在桶2中等。对于其他数据类型,它有点棘手。特别是,BIGINT的散列与BIGINT不同。并且字符串或复杂数据类型的散列将是从该值派生的某个数字,但不是任何人类可识别的数字。例如,如果user_id是STRING,则存储桶1中的user_id可能不会以0结尾。通常,基于散列分配行将使您在存储桶中进行均匀分布。

答案 2 :(得分:0)

查看语言手册here

它声明:

  

Hive如何在存储桶中分配行?通常,桶号由表达式hash_function(bucketing_column)mod num_buckets确定。 (那里也有一个'0x7FFFFFFF,但那并不重要)。 hash_function取决于bucketing列的类型。对于int,它很容易,hash_int(i)== i。例如,如果user_id是一个int,并且有10个桶,我们希望所有以0结尾的user_id都在桶1中,所有user_id以1结尾在桶2中,等等。对于其他数据类型,它是有点棘手。特别是,BIGINT的散列与BIGINT不同。并且字符串或复杂数据类型的散列将是从值中派生的某个数字,但不是人类可识别的任何数字。例如,如果user_id是STRING,那么存储桶1中的user_id可能不会以0结尾。通常,基于散列分配行将使您在存储桶中进行均匀分布。

在你的情况下,因为你是通过Id进行聚类,这是一个Int,然后你将它分成3个桶,只是看起来所有值都被散列到其中一个桶中。要确保这一点正常工作,请添加一些与文件中的ID不同的行,并增加桶的数量,看看这次是否将它们分成单独的文件。