Hive.GROUPING SETS

       如果說聚合函數(Simple UDAF / Generic UDAF)是HQL聚合數據查詢或分析的中樞處理器,那GROUP BY可以說是聚合函數的神經了,GROUP BY收集和傳遞材料,然後交給聚合函數們去處理。這些材料的組織形式顯得尤爲重要,它們表達着分析者想要的觀察維度或視角,管理着聚合函數們的操作對象。

       而分析者經常想要在一次分析中從多個維度去獲得分析數據,對包含多個維度或多級層次的分析,上卷(roll up)或下鑽(drill down)一類就很有分析價值。

       我們有時候可以從最細、最多的粒度去做一個查詢,然後把結果集導入Excel這個數據分析利器,用數據透視圖標進行“上卷”分析;但有時候也行不通,比如說UV這種需要去重的數據,在Excel裏用匯總方式進行上卷,就不是純粹的UV概念了。

       所以,對這種情形,在查詢過程中,我們就需要獲得已經下鑽和上卷的數據;如果只有GROUP BY子句,那我們可以寫出按各個維度或層次進行GROUP BY的查詢語句,然後再通過UNION子句把結果集拼湊起來,但是這樣的查詢語句顯得冗長、笨拙。

       爲此,HQL像其它很多SQL實現一樣,爲我們提供了GROUPINGSETS子句來簡化查詢語句的編寫,以下官方CWiki文檔很清晰地表達了GROUPING SETS的功能:

 

Aggregate Query with GROUPING SETS

Equivalent Aggregate Query with GROUP BY


SELECT a, b, SUM(c) FROM tab1 GROUP BY a, b GROUPING SETS ( (a,b) )


SELECT a, b, SUM(c) FROM tab1 GROUP BY a, b

SELECT a, b, SUM( c ) FROM tab1 GROUP BY a, b GROUPING SETS ( (a,b), a)


SELECT a, b, SUM( c ) FROM tab1 GROUP BY a, b
UNION
SELECT a, null, SUM( c ) FROM tab1 GROUP BY a


SELECT a,b, SUM( c ) FROM tab1 GROUP BY a, b GROUPING SETS (a,b)


SELECT a, null, SUM( c ) FROM tab1 GROUP BY a
UNION
SELECT null, b, SUM( c ) FROM tab1 GROUP BY b


SELECT a, b, SUM( c ) FROM tab1 GROUP BY a, b GROUPING SETS ( (a, b), a, b, ( ) )


SELECT a, b, SUM( c ) FROM tab1 GROUP BY a, b
UNION
SELECT a, null, SUM( c ) FROM tab1 GROUP BY a, null
UNION
SELECT null, b, SUM( c ) FROM tab1 GROUP BY null, b
UNION
SELECT null, null, SUM( c ) FROM tab1


       因爲涉及UNION操作,所以爲了遵循UNION對參與合併的數據集合的要求,GROUPING SETS會把在單個GROUP BY邏輯中沒有參與GROUP BY的那一列置爲NULL值,使它成爲常量佔位列。這樣聚合出來的結果,未被GROUP BY的列將顯示爲NULL。

       但是這樣的處理也會引起一個歧義性問題,如果我們分析的表有一些列沒有NOT NULL約束,那原始數據中,未被GROUP BY的列可能原本就會出現一些NULL值,這樣,GROUPING SETS出來的結果,我們沒有辦法去區分該列顯示的NULL值是原始數據出現的NULL值聚合的結果,還是你因爲這列沒有參與GROUP BY而被置爲NULL值的結果。

       爲了解決這個歧義問題,HQL又爲我們提供了一個Grouping__ID函數(請注意函數名中的下劃線是兩個!);這個函數沒有參數,在有GROUPING SETS子句的情況下,把它直接放在SELECT子句中,像其它列一樣,獨佔一列。它返回的結果是一個看起來像整形數值類型,其實是字符串的值,這個值使用了位圖策略(bitvector,位向量),即它的二進制形式中的每1位標示着對應列是否參與GROUP BY,如果某一列參與了GROUP BY,對應位就被置爲1,否則爲0,根據這個位向量值和對應列是否顯示爲NULL,我們就可以解決上面提到的歧義問題了。

       這樣一來,Grouping__ID函數返回值的範圍由查詢的字段數(除去聚合函數產生的列)決定,如果比如有3列,那位向量爲3位,最大值爲7。CWiki文檔提供了下面的示例:

       有下面一個表數據:

  Column1 (key)  

  Column2 (value)  

  1

  NULL

  1

  1

  2

  2

  3

  3

  3

  NULL

  4

  5

       我們用這樣的查詢語句去執行查詢:

SELECT key, value, GROUPING__ID, count(*) from T1 GROUP BY key,value WITH ROLLUP


       將得到如下查詢結果:

 

 

 

 

  NULL  

  NULL  

    0    

    6    

     1

  NULL

    1

    2

     1

  NULL

    3

    1

     1

    1

    3

    1

     2

  NULL

    1

    1

     2

    2

    3

    1

     3

  NULL

    1

    2

     3

  NULL

    3

    1

     3

     3

    3

    1

     4

  NULL

    1

    1

     4

     5

    3

    1

 

       官方文檔沒有明確說明這個位向量和各列的高低位對應關係,但是從示例我們可以看到,這個位向量的低位對應SELECT子句中的第1列(非聚合列),高位對應最後1列(非聚合列)。

       上面的查詢用到了WITH ROLLUP子句,它對應SQL中的上卷操作,其實它就是GROUPINGSETS的特例,對應上面第一個表格中的第4種情形;根據官方的CWiki文檔解釋,GROUP BY 子句加上ROLLUP 子句可用於計算從一個維度進行層級聚合的操作:

GROUP BY a, b, c with ROLLUP assumes that the hierarchy is"a" drilling down to "b" drilling down to "c".


       類似地還有WITH CUBE子句,對應SQL中的CUBE操作,它完成對字段列中的所有可能組合(全序集?)進行GROUP BY的功能,正如官方CWiki文檔的解釋:

GROUP BY a, b, c WITH CUBE 等同於
GROUP BY a, b, c GROUPING SETS ( (a, b, c), (a, b), (b, c), (a, c),(a), (b), (c), ( ))

 

       GROUPING SETS增強了GROUP BY的查詢表達能力,ROLLUP和CUBE又增強了GROUPING SETS的查詢表達能力,這樣一來,GROUP BY的形態也變得多樣化了,讓我們能夠在查詢階段就實現更多的分析角度。

       還需留意的是:Hive從0.10.0版本纔開始有GROUPING SETS的。


官方CWiki文檔請點我


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章