Hive 之 查詢 04-分桶及抽樣查詢
一、 分桶表數據存儲
分區針對的是數據的存儲路徑, 分桶針對的是數據文件;
分區提供一個隔離數據和優化查詢的便利方式。 不過, 並非所有的數據集都可以形成合理的分區。 特別是要確定合適的劃分大小這個問題。
【注】分桶類似於 Hadoop 裏面的分區;
如:
創建分桶表:
hive (default)> create table stu_buck(
> id int,
> name string)
> clustered by(id)
> into 4 buckets
> row format delimited fields terminated by '\t';
OK
Time taken: 2.17 seconds
查看錶結構:
hive (default)> desc formatted stu_buck;
OK
... ...
Num Buckets: 4
Bucket Columns: [id]
... ...
Time taken: 0.449 seconds, Fetched: 28 row(s)
導入數據:
hive (default)> load data local inpath
> '/opt/module/data/student.txt'
> into table stu_buck;
Loading data to table default.stu_buck
Table default.stu_buck stats: [numFiles=1, totalSize=151]
OK
Time taken: 0.767 seconds
查看數據:
hive (default)> select * from stu_buck;
OK
stu_buck.id stu_buck.name
1001 ss1
1002 ss2
1003 ss3
1004 ss4
1005 ss5
1006 ss6
1007 ss7
1008 ss8
1009 ss9
1010 ss10
1011 ss11
1012 ss12
1013 ss13
1014 ss14
1015 ss15
1016 ss16
Time taken: 0.324 seconds, Fetched: 16 row(s)
由於 load 命令加載數據, 實際上使用的是 hadoop 的 put 命令, 所以數據並沒有被分到四個桶裏面, 而是一個文件。 可以查看 hadoop 的 /user/hive/warehouse/stu_buck/
路徑下只有一個 student.txt
文件。
所以這種方式不行。
另一種方式: 創建一個普通表(不分區、 不分桶):
hive (default)> create table stu(
> id int,
> name string
> )
> row format delimited fields terminated by '\t';
OK
Time taken: 0.038 seconds
然後加載數據到 stu
表中:
hive (default)> load data local inpath
> '/opt/module/data/student.txt'
> into table stu;
Loading data to table default.stu
Table default.stu stats: [numFiles=4, numRows=0, totalSize=232, rawDataSize=0]
OK
Time taken: 0.26 seconds
然後使用下面這種方式將 stu
中的數據導入到 stu_buck
中(爲了讓它走 MR, 這樣 stu_buck
才能讀到 id 這個分桶字段):
hive (default)> insert into table stu_buck
> select * from stu;
... ...
OK
stu.id stu.name
Time taken: 29.734 seconds
結果發現 stu_buck
的表裏面依舊是一個文件, 並沒有分桶。
我們需要設置些屬性然後再導入數據:
hive (default)> set hive.enforce.bucketing=true;
hive (default)> set set mapreduce.job.reducers=-1;
分別設置了強制分桶, 並將 Reducer 的個數設置爲 -1(不限制);
然後再導入數據:
hive (default)> insert into table stu_buck
> select * from stu;
再次查看 Hadoop 上/user/hive/warehouse/stu_buck/
路徑下有四個文件:
[root@hadoop102 data]# hadoop fs -ls /user/hive/warehouse/stu_buck/
Found 4 items
-rwxr-xr-x 3 root supergroup 38 2020-04-02 00:49 /user/hive/warehouse/stu_buck/000000_0
-rwxr-xr-x 3 root supergroup 37 2020-04-02 00:49 /user/hive/warehouse/stu_buck/000001_1
-rwxr-xr-x 3 root supergroup 38 2020-04-02 00:48 /user/hive/warehouse/stu_buck/000002_0
-rwxr-xr-x 3 root supergroup 38 2020-04-02 00:49 /user/hive/warehouse/stu_buck/000003_0
查詢數據表中的數據:
hive (default)> select * from stu_buck;
OK
stu_buck.id stu_buck.name
1016 ss16
1012 ss12
1008 ss8
1004 ss4
1009 ss9
1005 ss5
1001 ss1
1013 ss13
1010 ss10
1002 ss2
1006 ss6
1014 ss14
1003 ss3
1011 ss11
1007 ss7
1015 ss15
Time taken: 0.032 seconds, Fetched: 16 row(s)
二、 分桶抽樣查詢
對於非常大的數據集,有時用戶需要使用的是一個具有代表性的查詢結果而不是全部結果。 Hive 可以通過對錶進行抽樣來滿足這個需求。
查詢表 stu_buck
中的數據
hive (default)> select * from stu_buck
> tablesample(bucket 1 out of 4 on id);
OK
stu_buck.id stu_buck.name
1016 ss16
1012 ss12
1008 ss8
1004 ss4
Time taken: 1.977 seconds, Fetched: 4 row(s)
注:tablesample
是抽樣語句,語法: TABLESAMPLE(BUCKET x OUT OF y) 。
y 必須是 table 總 bucket 數的倍數或者因子。 hive 根據 y 的大小,決定抽樣的比例。例如, table 總共分了 4 份,當 y=2 時,抽取(4/2=)2 個 bucket 的數據,當 y=8 時,抽取(4/8=)1/2 個 bucket 的數據。
x 表示從哪個 bucket 開始抽取,如果需要取多個桶,以後的桶號爲當前桶號加上 y。
例如, table 總 bucket 數爲 4,tablesample(bucket 1 out of 2)
,表示總共抽取(4/2=)2 個 bucket 的數據,抽取第 1(x) 個和第 3(x+y) 個 bucket 的數據。
【注意】x 的值必須小於等於 y 的值,否則:
hive (default)> select * from stu_buck
> tablesample(bucket 5 out of 4 on id);
FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause
for table stu_buck