Hive 的資料抽樣
最近在做Hive的資料抽樣,基於以下考慮:
-
效率:資料量大的時候,可以給Hive 的使用者提供抽樣資料,供他們開發、測試,提高效率。
-
安全:有些場景,不便於提供全量資料給開發者,但是又不能影響建模效果,這時,就需要隨機抽樣資料給開發者。
要求:
-
隨機
-
抽取資料量可控
-
分割槽資訊需要保留,資料整體隨機,分割槽內也要隨機
1. 抽樣方案
1.1 方案一:Block Sampling
Hive 本身提供了抽樣函式,使用TABLESAMPLE 抽取指定的 行數/比例/大小 ,舉例:
CREATE TABLE XXX AS SELECT * FROM YYY TABLESAMPLE(1000 ROWS); CREATE TABLE XXX AS SELECT * FROM YYY TABLESAMPLE (20 PERCENT); // 測試未生效 CREATE TABLE XXX AS SELECT * FROM YYY TABLESAMPLE(1M);// 測試未生效
缺點: 不隨機 。該方法實際上是按照檔案中的順序返回資料,對分割槽表,從頭開始抽取,可能造成只有前面幾個分割槽的資料。
優點:速度快。
1.2 方案二:分桶表抽樣 (Smapling Bucketized Table)
利用分桶表,隨機分到多個桶裡,然後抽取指定的一個桶。舉例:隨機分到10個桶,抽取第一個桶。
CREATE TABLE XXX AS SELECT * FROM YYY TABLESAMPLE (BUCKET 1 OUT OF 10 ON rand());
優點:隨機,測試發現,速度比方法3的
rand()
快。
1.3 方案三:隨機抽樣 rand
原理:利用
rand()
函式進行抽取,
rand()
返回一個0到1之間的double 值。
法1
CREATE TABLE XXX AS SELECT * FROM YYY ORDER BY rand() limit 10000
此時,可以提供真正的隨機抽樣,但是,需要在單個
reducer
中進行總排序,
速度慢
。
法2
CREATE TABLE XXX AS SELECT * FROM YYY SORT BY rand() limit 10000
Hive 提供了
sort by
,
sort by
提供了單個
reducer
內的排序功能,但不保證整體有序,上面的語句是不保證隨機性
的。
法3
CREATE TABLE XXX AS SELECT * FROM YYY where rand()<0.002 distribute by rand() sort by rand() limit 10000;
where
條件首先進行一次
map
端的優化,減少
reducer
需要處理的資料量,提高速度。
distribute by
將資料隨機分佈,然後在每個
reducer
內進行隨機排序,最終取10000條資料(如果資料量不足,可以提高
where
條件的
rand
過濾值)。
缺點: 速度慢
法4
CREATE TABLE XXX AS SELECT * FROM YYY where rand()<0.002 cluster by rand() limit 10000;
cluster by
的功能是
distribute by
和
sort by
的功能相結合,在上面的例子中,
distribute by rand() sort by rand()
進行了兩次隨機,
cluster by rand()
僅一次隨機,那麼,會影響最終的抽樣結果嗎?
2. 分割槽
但是,上面的方法,會 丟失掉分割槽資訊 !
所以,需要結合動態分割槽:
-
step1: create table
-
step2: 利用動態分割槽,插入select 出來的結果。
set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; INSERT INTO TABLE XXX partition(thedate) SELECT * FROM YYY TABLESAMPLE (BUCKET 1 OUT OF 10 ON rand());