HIVE窗口函數的理解

set hive.cli.print.header=true;

HIVE的窗口函數,對於每一條數據通過窗口滑動,對在窗口內的數據進行聚合等操作。

假設窗口大小爲2,那麼對每一條數據就以大小爲2的窗口滑動。

第一條數據的窗口:

然後滑動窗口到第二條數據:

對每二條、第三條、第四條數據進行窗口滑動,進行相應的聚合等操作,將結果放入對應行的cum_money列。

 

OVER()函數是窗口函數。一般與聚合函數/lag/lead/ntile/row_number/rank/dense_rank等函數搭配使用。

這裏通過示例加以說明:

假設table_sale表的數據如下:

orderdate sale_money clientName
2020-01-01 2.0 a
2020-01-02 1.0 b
2020-01-01 3.0 b
2020-01-02 5.0 a

1 不加條件的OVER函數

問題:統計客戶總消費金額

select *,sum(sale_money) over() as 'cum_money' from table_sale;

執行結果如下:

orderdate sale_money clientName cum_money
2020-01-01 2.0 a 11.0
2020-01-02 1.0 b 11.0
2020-01-01 3.0 b 11.0
2020-01-02 5.0 a 11.0

而HIVE是如何實現累計的呢?

對於OVER()函數而言,它會爲每一條數據進行開窗操作,不加參數時每一條數據的窗口大小是相同的。每一個窗口內部都會執行sum([窗口大小的數據集合])函數。

這裏沒有對OVER()函數加任何條件,從而每一條數據的開窗大小都爲4。進行sum()操作如下:

orderdate sale_money clientName cum_money
2020-01-01 2.0 a sum([2.0,1.0,3.0,5.0])
2020-01-02 1.0 b sum([2.0,1.0,3.0,5.0])
2020-01-01 3.0 b sum([2.0,1.0,3.0,5.0])
2020-01-02 5.0 a sum([2.0,1.0,3.0,5.0])

2 加排序條件的OVER函數

問題:統計客戶累計消費情況

select *,sum(sale_money) over(order by orderdate) as 'cum_money' from table_sale;

裏面對OVER函數加了條件,首先會對數據進行排序操作,此時加了排序條件每一條數據的窗口大小是不同的

對於第一條數據而言,它的窗口大小爲1(因爲它前面沒有數據),爲第一條數據開窗後,就開始執行相應的聚合函數,然後賦予到第一行中。

orderdate sale_money clientName cum_money
2020-01-01 2.0 a sum([2.0])
2020-01-01 3.0 b  
2020-01-02 1.0 b  
2020-01-02 5.0 a  

對於第二條數據,因爲它的前面已經有了a客戶的數據,再加上自身的數據,從而當前窗口大小爲2,然後就開啓大小爲2的窗口,進行聚合操作,即sum([2.0,,3.0])

orderdate sale_money clientName cum_money
2020-01-01 2.0 a sum([2.0])
2020-01-01 3.0 b sum([2.0,3.0])
2020-01-02 1.0 b  
2020-01-02 5.0 a  

對於第三條數據,則開啓大小爲3的窗口,第四條條數據則開啓大小爲4的窗口:

orderdate sale_money clientName cum_money
2020-01-01 2.0 a sum([2.0])
2020-01-01 3.0 b sum([2.0,3.0])
2020-01-02 1.0 b sum([2.0,3.0,1.0])
2020-01-02 5.0 a sum([2.0,3.0,1.0,5.0])

從而完成了累計操作。

3 加分區條件的OVER函數

問題:統計每一個客戶總消費情況

select *,sum(sale_money) over(partition by clientName) as 'cum_money' from table_sale;

執行sum(sale_money) over(parition by name)部分時,首先對數據集進行分區(分組)操作,此時每一條數據集的窗口大小爲所在分區的大小。如對a客戶分區,a客戶有2條數據集,從而窗口大小爲2。從而對於sum()函數執行情況如下:

orderdate sale_money clientName cum_money
2020-01-01 2.0 a sum([2.0,5.0])
2020-01-02 5.0 a sum([2.0,5.0])
2020-01-01 3.0 b sum([3.0,1.0])
2020-01-02 1.0 b sum([3.0,1.0])


4 加分區排序條件的OVER函數

問題:統計每一個客戶累計消費情況

select *,
    sum(sale_money) over(partition by clientName order by orderdate) as 'cum_money' 
from table_sale;

首先OVER函數對數據執行分區操作,然後對數據進行排序操作。而加了排序操作使得分區內部的每一條數據的窗口大小是不同的。對於sum()函數執行情況如下:

orderdate sale_money clientName cum_money
2020-01-01 2.0 a sum([2.0])
2020-01-02 5.0 a sum([2.0,5.0])
2020-01-01 3.0 b sum([3.0])
2020-01-02 1.0 b sum([3.0,1.0])

5 加窗口大小條件的OVER函數

這裏先對OVER函數內部的若干參數進行說明:

  • CURRENT ROW:當前行
  • n PRECEDING:往前n行數據
  • n FOLLOWING:往後n行數據
  • UNBOUNDED:起點,UNBOUNDED PRECEDING 表示從前面的起點, UNBOUNDED FOLLOWING表示到後面的終點

問題:統計相鄰兩條數據的消費總額

select *,
    sum(sale_money) over(rows between 1 preceding and current row) as 'cum_money' 
from table_sale;

該問題的答案忽略了邊界問題,請忽略。

1 preceding : 指的是前一行;current row : 當前行,從而限定了窗口大小爲2。此時sum()函數執行如下:

orderdate sale_money clientName cum_money
2020-01-01 2.0 a 0
2020-01-02 5.0 a 2.0
2020-01-01 3.0 b 0
2020-01-02 1.0 b 3.0

6 LAG/LEAD函數的使用

  • LAG(col,n):往前n行數據
  • LEAD(col,n):往後n行數據

LAG和LEAD()要與OVER()函數一起使用。

問題:查看客戶前一天消費金額。

select *,
    lag(sale_money,1,0) over(partition by clientName order by orderdate) as 'yesterdayMoney' 
from table_sale;

-- 也可以寫成這樣的

select *,
    lag(sale_money,1,0) over(distirbution by clientName sort by orderdate) as 'yesterdayMoney' 
from table_sale;

lag(sale_money,1,0):取窗口內的前1天sale_money數據,若無數據,則用0替代。

查詢結果爲:

orderdate sale_money clientName cum_money
2020-01-01 2.0 a 0
2020-01-02 5.0 a 2.0
2020-01-01 3.0 b 0
2020-01-02 1.0 b 3.0

對於LEAD函數也是一樣的理解,如:

問題:查看客戶下一天消費金額。

select *,
    lead(sale_money,1,0) over(partition by clientName order by orderdate) as 'nextMoney' 
from table_sale;

lead(sale_money,1,0):取窗口內的下1天sale_money數據,若無數據,則用0替代。

orderdate sale_money clientName cum_money
2020-01-01 2.0 a 5.0
2020-01-02 5.0 a 0
2020-01-01 3.0 b 1.0
2020-01-02 1.0 b 0

就這麼多了,希望對大家有幫助。

若有錯誤,還請指正。

參考:

1 嗶哩嗶哩的尚硅谷視頻:https://www.bilibili.com/video/BV1z4411y7C2?p=44

2 《Hive編程指南》

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