Hive TOP N 實現方法

本文主要轉至:http://www.cnblogs.com/skyl/p/4776083.htmlhtml

1).Hive中Select Top N的實現sql

Hive中使用 Order by + Limit 能夠很容易地實現Select Top N。數據庫

hive默認的order by實現只會用1個reduce作全局排序,這在數據量大的時候job運行效率很是低。hive在0.12版本引入了parallel order by,也就是經過sampling的方式實現並行(即基於TotalOrderPartitioner)。具體開關參數是hive.optimize.sampling.orderby。可是若是使用這個參數仍是極可能碰到問題的:apache

  • 首先若是order by字段自己取值範圍過少,會形成Split points are out of order錯誤。這是由於,假設job中reduce數量爲r的話,那麼TotalOrderPartitioner須要order by字段的取值至少要有r - 1個。那麼這樣一來還須要關心reduce數量,增長了開發負擔,並且若是把reduce數量設的很小,優化的效果就不太明顯了。
  • 其次,設置這個參數還可能形成聚會函數出錯,這個問題只在比較新的hive版本中解決了。

實際上,若是隻是取top n而非全局排序,只須要使用sort by col limit n的寫法就能達到很好的效果。sort by語法自己保證每一個reduce內數據有序,這樣就等因而作並行排序。而limit n則保證兩件事:一方面是使得並行排序時每一個reduce的輸出記錄數只是n,也就是先在每一個reduce內部作top n(能夠explain一下看看執行計劃更加清楚);另一方面,等局部top n完成以後,再起一輪job,用1個reduce作全局top n,這個時候雖然不是並行排序,可是處理的數據量也已經大大減小,不會形成效率問題了。固然,若是本身實現mapreduce,能夠在mapper任務內維護最小最大堆,直接在map端實現並行的top n,再輸出給1個reducer作全局top n,只須要一輪job便可完成。不過若是n的大小沒有限制極可能會撐爆內存,並且即便沒有內存問題,實現也比較複雜,因此hive中沒有實現這樣的Operator,而是用上面描述的方式解決。畢竟在reduce端作top n,排序問題就已經在MR框架層面解決了,只須要考慮limit便可。api

從執行計劃explain中能夠看出Sort by Limit N啓動了兩個MR Job。第一個Job是在每一個Reduce中作局部排序,而後分別取Top N。假設啓動了M個reduce,第二個Job再對M個Reduce分別局部排好序的總計M * N條數據作全局排序,再取最終的Top N,從而獲得想要的結果。這樣就能夠大大提升Select Top N的效率。app

set mapred.reduce.tasks=3;
select * from tea sort by age limit 3;

除了對所有數據取top n,分組top n也是常見場景,好比學生成績表取每一個學科前三名,用戶點擊流數據取每一個用戶最先的幾個點擊等等。若是每一個分組須要排序的數據量不大,那麼能夠用窗口函數解決,或者在不支持窗口函數的比較老的hive版本本身實現udf。可是若是每一個分組自己很大,仍是會很慢。若是追求性能的話,一樣能夠借鑑sort by limit的寫法,在分組個數很少且固定的狀況下直接將分組寫死。好比「取每一個性別訪問次數最多的10人」相似這樣的情景,就能夠拆解爲「男性訪問次數最多的10人 + 女性訪問次數最多的10人」。框架

 

2).Hive中分組  Select Top N的實現;函數

drop table tmp_users_time;  
create table tmp_users_time   
as  
select * from  
(  
  select u.*,row_numwer() over(distribute by grade sort by score desc) sn  
  from users u  
)tu  
where tu.sn > 2;  

或者

insert into table users_time_top  
select tu.grade,tu.score  
from  
(  
  select u.*,row_number() over(distribute by grade sort by score desc) sn  
  from users u  
)tu  
where tu.sn > 2;

 

3).hive中的分號字符 -- 此部份內容在最新版的HIVE中已修復;oop

分號是SQL語句結束標記,在HiveQL中也是,可是在HiveQL中,對分號的識別沒有那麼智慧,例如:性能

hive> select concat(';','a');
--會報異常NoViableAltException(-1@[]),解決方案:
最新版的HIVE輸出的結果爲:';a'

hive> select concat('\073','a');
--分號的ASCII值是59,八進制爲073.只能使用八進制,對於十六進制無效
--concat(str1,str2)做用爲拼接字符串
最新版Hive的輸出結果:';a'

3).Hive客戶端默認配置

如下操做都可在$HIVE_HOME/bin/.hiverc文件中保存,設置爲默認參數:

set hive.mapred.mode=strict;
//開啓strict模式,如下狀況報錯:(1)沒有limit限制的order by語句.(2)動態分區插入

set hive.cli.print.current.db=true;
//顯示當前工做的數據庫

set hive.cli.print.header=true;
//顯示列名

set mapred.reduce.tasks=3;
//設置reduce的個數

set hive.exec.reducers.bytes.per.reducer;
//多少字節開一個reducer,默認256000000

set hive.exec.dynamic.partition.mode=strict;
//該模式下必須指定一個靜態分區
相關文章
相關標籤/搜索