同上篇hadoop mapreduce 實現分組top n介紹一樣,這次學習hive實現分組top n。
在資料處理中,經常會碰到這樣乙個場景,對錶資料按照某一字段分組,然後找出各自組內最大的幾條記錄情形。針對這種分組top n問題,我們利用hive、mapreduce等多種工具實現一下。
對類如下users表記錄,取出不同grade下得分最多的兩條記錄
id grade score
1 a 10
2 a 40
3 b 30
4 c 20
5 b 10
6 d 40
7 a 30
8 c 20
9 b 10
10 d 40
11 c 30
12 d 20
先對users根據grade進行分割槽,然後根據score進行倒序排序,再應用row_number函式從每個分割槽中篩選出各個分割槽的前兩條記錄。
with groupsort as (
select *, rid = row_number() over
(partition by grade order by score desc) from users
)select id, grade, score from groupsort where rid <= 2;
這裡使用with as抽離子查詢部分,相當於定義乙個sql片斷,該sql片斷會被整個sql語句所用到。有的時候,是為了讓sql語句的可讀性、優化性更高些,因為如果withas短語所定義的表名被呼叫兩次以上,優化器會自動將with as短語所獲取的資料放入乙個temp表裡,如果只是被呼叫一次,則不會。
然後使用row_number() over(partition by clo1 order by clo2 desc) 方法來對clo1分組並且計算同組clo2最大的一條或幾條記錄。
我們知道hive允許執行hql語句,雖說hql和sql有很多相同之處,但還是有許多差別之處,以row_number()為例:
在hive低版本中,row_number()在hive中是乙個函式,必須帶乙個或者多個列引數,如row_number(col1, ....),它的作用是按指定的列進行分組生成行序列,在row_number(a,b) 時,若兩條記錄的a,b列相同,則行序列+1,否則重新計數。而在高版本中就取消了這一限制,寫法和現在的sql一致,同時,因為hive是基於mapreaduce的,必須保證row_number執行是在reduce中,並且row_number中使用的列中,列值相同的記錄要再同乙個reduce中,否則row_number的行為是無意義的。
將目標資料存入臨時表中
drop table tmp_users_time;
create table tmp_users_time
asselect * from
(select u.*,row_numwer() over(distribute by grade sort by score desc) sn
from users u
)tuwhere tu.sn > 2;
或者將資料新增到記錄時刻top的大表中,預設大表自動新增時間
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
)tuwhere tu.sn > 2;
select u.*,row_number(u.score) as sn
from
(select grade,score from users distribute by grade sort by score desc
)uwhere row_number(score) > 2;
這裡有兩點需要說明:
使用子查詢保證row_number在reduce端執行。
使用distribute by grade sort by score desc來保證grade相同的記錄被分配到相同的reduce中。
今天也學習了一種使用hive udf函式實現top n的方法,先對grade和score排序,然後對grade計數,在where條件過濾出grade列計數器大於n的行即可。
(1)定義udf:
package com.example.hive.udf;
import org.apache.hadoop.hive.ql.exec.udf;
public final class rank extends udf
return this.counter++;
}}
(2)註冊jar、建表、導資料,查詢:
add jar rank.jar;
create temporary function rank as 'com.example.hive.udf.rank';
create table users(id int,grade string,score int) row format delimited fields terminated by ' ';
load data local inpath 'users.txt' overwrite into table users;
select grade,score from (
select grade,rank(grade) cnum,score from (
select id, grade, score from users distribute by grade sort by score desc
)u)b where cnum < 2;
這種是臨時轉換udf,永久的需要單獨設定。 分組Top N 問題
今天面試,面試官給了這樣乙個場景 有兩張表,一張表存放車隊id,班組id,司機id 另一種表存放司機id,運營時間,運營里程 要查詢出7月份每個車隊每個班組裡的 top 3 這就要用到row number 函式 首先按需求建兩張表 create table demo of topn car comp...
SQL中Group分組獲取Top N 方法實現
有產品表,包含id,name,city,addtime四個字段,因報表需要按城市分組,統計每個城市的最新10個產品,便向該表中插入了100萬資料,做了如下系列測試 create table dbo products id int identity 1,1 not null name nvarchar...
SQL2000表分組問題
現sql2000伺服器上有一張表,格式如下 檔案內容 檔案組 1 a2 a 3 a4 b 5 c6 d 7 e8 e 9 f要實現將表內容更新為 檔案內容 檔案組 a1 a 2 a3 a b4 b c5 c d6 d e7 e 8 ef 9 f意思是將分組資訊直接加在檔案內容之中?如果不用游標,不知...