閱讀723 返回首頁    go 技術社區[雲棲]


阿裏雲大數據利器Maxcompute學習之--窗口函數實現分組TopN

看到很多用戶經常會問如何對分組內進行排序。
官方文檔:https://help.aliyun.com/document_detail/34994.html?spm=5176.doc27891.6.611.Q1bk3j
例如需求:
1. odps 裏麵能否做排名操作,比如一個表裏麵有 用戶ID 和 金額 兩個字段,用金額大小排序的話,我如何計算用戶的排名(金額最大的是 第一名 ,以此類推)
2. 計算每個金融產品的最大投資者,或者前幾名

類似這一類的需求,我們總結為實現分組內的排序,取TopN,那麼在hive中有兩個個函數可以分開實現
first_value: 取分組內排序後,截止到當前行,第一個值,
row_number():實現組內排序,並對組內行進行標記行號。
那在odps中沒有first_value這個函數,但是同樣可以實現top1的需求。下麵用一個大家最愛的公司員工表來舉例實現

員工表:

empno ename job mgr hiredate sal comm deptno
7839 KING PRESIDENT NULL 1981-11-17 00:00:00 5000.0 NULL 10
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975.0 NULL 20
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850.0 NULL 30
7788 SCOTT ANALYST 7566 1987-07-13 01:00:00 3000.0 NULL 20
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450.0 NULL 10
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800.0 NULL 20
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000.0 NULL 20
7876 ADAMS CLERK 7788 1987-07-13 01:00:00 1100.0 NULL 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950.0 NULL 30
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300.0 NULL 10
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600.0 300.0 30
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250.0 1400.0 30
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500.0 0.0 30
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250.0 500.0 30

使用row_number()對相同 job 的薪水sal 進行

排序,取組內最大,等不及了,直接上sql

```select * from (
select job,sal,
row_number() over(partition by job order by sal desc) as rn from emp
) a where rn=1;
//partition by 跟分組字段
//order by 跟排序字段+升降關鍵字 默認升序排列。



結果:

job | sal  | rn    |
-----|----------|------------
 ANALYST | 3000.0     | 1          
CLERK | 1300.0     | 1          
 MANAGER | 2975.0     | 1          
 PRESIDENT | 5000.0     | 1          
 SALESMAN | 1600.0     | 1          

同理如果想實現topN,那把rn=1改成rn<N,例如我想看每個崗位job前兩個工資最多的人,sql如下

select * from (
    select job,ename,sal,
     row_number() over(partition by job order by sal desc) as rn  from emp
 ) a where rn<3;



結果:



job | ename | sal     | rn         |
----|-------|----------|------------
ANALYST | SCOTT | 3000.0     | 1          |
ANALYST | FORD  | 3000.0     | 2          |
 CLERK | MILLER | 1300.0     | 1          |
CLERK | ADAMS | 1100.0     | 2          |
 MANAGER | JONES | 2975.0     | 1          |
 MANAGER | BLAKE | 2850.0     | 2          |
PRESIDENT | KING  | 5000.0     | 1          |
 SALESMAN | ALLEN | 1600.0     | 1          |
SALESMAN | TURNER | 1500.0     | 2          |
+-----+-------+------------+------------+
那這是一個簡單的例子。
對於類似需求可以用這個方法來實現TopN的計算。
注意:這種方法對於數量級不是很大的或者分組比較均勻的大數據量實用,
如果分組鍵值不均勻,導致單個或者幾個鍵值比較大,那會有數據傾斜的問題。此時我們可以從sql上優化寫法,例如可以排查哪幾個鍵值比較大單獨拉出來一個任務執行。


最後更新:2017-06-27 22:32:09

  上一篇:go  搭建百萬級別郵件發送平台
  下一篇:go  如何給背景圖像使用CSS3變形