分組Top N問題 三 sql及Hive實現

2021-07-24 21:42:06 字數 3060 閱讀 5626

同上篇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意思是將分組資訊直接加在檔案內容之中?如果不用游標,不知...