1. 程式人生 > >Hive學習之抽樣(Sampling)

Hive學習之抽樣(Sampling)

      當資料量特別大時,對全體資料進行處理存在困難時,抽樣就顯得尤其重要了。抽樣可以從被抽取的資料中估計和推斷出整體的特性,是科學實驗、質量檢驗、社會調查普遍採用的一種經濟有效的工作和研究方法

      Hive支援桶表抽樣和塊抽樣,下面分別學習。所謂桶表指的是在建立表時使用CLUSTERED BY子句建立了桶的表。桶表抽樣的語法如下:

table_sample: TABLESAMPLE (BUCKET x OUT OF y [ON colname])

      TABLESAMPLE子句允許使用者編寫用於資料抽樣而不是整個表的查詢,該子句出現FROM子句中,可用於任何表中。桶編號從1開始,colname表明抽取樣本的列,可以是非分割槽列中的任意一列,或者使用rand()表明在整個行中抽取樣本而不是單個列。在colname上分桶的行隨機進入1到y個桶中,返回屬於桶x的行。下面的例子中,返回32個桶中的第3個桶中的行:

SELECT *
FROM source TABLESAMPLE(BUCKET 3 OUT OF 32 ON rand()) s;

      通常情況下,TABLESAMPLE將會掃描整個表然後抽取樣本,顯然這種做法效率不是很高。替代方法是,由於在使用CLUSTERED BY時指定了分桶的列,如果抽樣時TABLESAMPLE子句中指定的列匹配CLUSTERED BY子句中的列,TABLESAMPLE只掃描表中要求的分割槽。假如上面的例子中,source表在建立時使用了CLUSTEREDBY id INTO 32 BUCKETS,那麼下面的語句將返回第3個和第19個簇中的行,因為每個桶由(32/16)=2個簇組成。為什麼是3和19呢,因為要返回的是第3個桶,而每個桶由原來的2個簇組成,第3個桶就由原來的第3個和19個簇組成,根據簡單的雜湊演算法(3%16=19%16)。

TABLESAMPLE(BUCKET 3 OUT OF 16 ON id)

      相反,下面的語句將會返回第3個簇的一半,因為每個桶由(32/64)=1/2個簇組成。

TABLESAMPLE(BUCKET 3 OUT OF 64 ON id)

      從Hive-0.8開始可以使用塊抽樣,語法為:

block_sample: TABLESAMPLE (n PERCENT)

      該語句允許抽取資料大小的至少n%(不是行數,而是資料大小)做為輸入,支援CombineHiveInputFormat而一些特殊的壓縮格式是不能夠被處理的,如果抽樣失敗,MapReduce作業的輸入將是整個表。由於在HDFS塊層級進行抽樣,所以抽樣粒度為塊的大小,例如如果塊大小為256MB,即使輸入的n%僅為100MB,也會得到256MB的資料。下面的例子中輸入的0.1%或更多將用於查詢:

SELECT *
FROM source TABLESAMPLE(0.1 PERCENT) s;

      如果希望在不同的塊中抽取相同的資料,可以改變下面的引數:

set hive.sample.seednumber=<INTEGER>;

      也可以指定讀取資料的長度,該方法與PERCENT抽樣具有一樣的限制,為什麼有相同的限制,是因為該語法僅將百分比改為了具體值,但沒有改變基於塊抽樣這一前提條件。該語法為:

block_sample: TABLESAMPLE (ByteLengthLiteral)
 
ByteLengthLiteral : (Digit)+ ('b' | 'B' | 'k' | 'K' | 'm' | 'M' | 'g' | 'G')

下面的例子中輸入的100M或更多將用於查詢:

SELECT *
FROM source TABLESAMPLE(100M) s;

      Hive也支援基於行數的輸入限制,當效果與上面介紹的兩個不同。首先不需要CombineHiveInputFormat,這意味著可以被用在非原生表中。其次行數被用在每個split中。因此總的行數根據輸入的split數而變化很大。語法格式為:

block_sample: TABLESAMPLE (n ROWS)

      例如下面的查詢將從每個split中抽取10行:

SELECT * FROM source TABLESAMPLE(10 ROWS);