Hive窗口函數row number的用法, 你肯定都會吧!

2021-02-20 Java大數據與數據倉庫

row_number

前面我們介紹窗口函數的時候說到了窗口函數的使用場景,我們也給它起了一個名字進行區分,通用窗口函數和特殊窗口函數,今天我們就來看一下排序相關的窗口函數,因為是窗口函數,並且我們說它是用來排序的,我們大概也能猜到它就是用來對窗口內的數據進行排序的

其實關於排序我們前面也介紹過order by,sort by 等排序的方式Hive語法之常見排序方式,為什麼還有窗口函數進行排序的,因為前面的order by,sort by 等雖然可以排序但是不能給我們返回排序的值(名次),如果你用過mysql 的話,這個時候你就知道寫存儲過程或者使用自定義變量來完成這個功能,row number 也是一樣的道理,可以按照我們自定義的排序規則,返回對應的排序先後順序的值

所以我們認為row_number是窗口排序函數,但是hive 也沒有提供非窗口的排序函數,但是我們前面說過了如果沒有窗口的定義中沒有partition by 那就是將整個數據輸入當成一個窗口,那麼這種情況下我們也可以使用窗口排序函數完成全局排序。

測試數據

下面有一份測試數據id,dept,salary,然後我們就使用這份測試數據學習我們的窗口排序函數

1,銷售,10000
2,銷售,14000
3,銷售,10000
4,後端,20000
5,後端,25000
6,後端,32000
7,AI,40000
8,AI,35000
9,AI,60000
10,數倉,20000
11,數倉,30000
12,數倉,32000
13,數倉,42000

create table ods_num_window(
    id string,
    dept string,
    salary int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
LOAD DATA LOCAL INPATH '/Users/liuwenqiang/workspace/hive/number.txt' OVERWRITE INTO TABLE ods_num_window;

從例子中學習 row_number每個部門的員工按照工資降序排序

select
    *,row_number() over(partition by dept order by salary desc) as rn
from
    ods_num_window
;

我們看到每個部門都有自己的第一名,明顯的可以看到排序是發生在每個部門內部的

全部的員工按照工資降序排序

select
    *,row_number() over(order by salary desc) as rn
from
    ods_num_window
;

當我們沒有定義partition by 子句的時候,我們的所有數據都放在一個窗口裡面,這個時候我們的排序就是全局排序,其實如果你仔細看過我們的Hive語法之窗口函數初識這一節的話,你就知道partition by 其實是定義了子窗口,如果沒有子窗口的話,那就就是一個窗口,如果所有的數據都放在一個窗口的話那就是全局排序

取每個部門的工資前兩名

這個是row_number()  函數非常常見的使用場景top-N,其實如果你仔細看過我們的Hive語法之窗口函數初識這一節的話,你就知道partition by 其實是定義了子窗口,那其實這裡的top-N,本質上是子窗口的的top-N

select
    *
from(
   select
       *,row_number() over(partition by dept order by salary desc) as rn
   from
       ods_num_window
) tmp
where
    rn <=2
;

其實這個的實現方式就是我們對數據在子窗口內進行排序,然後選擇出我們我們需要的數據,也就是這裡的rn <=2

rank 和 dense_rank

其實這兩個窗口函數和row_number 是一樣的,都是窗口排序函數,既然這樣那為什麼還有這兩個函數呢,存在即合理,我們看一下row_number 函數,這次我們採用升序排序

select
    *,row_number() over(partition by dept order by salary) as rn
from
    ods_num_window
;

我們看到在銷售部門有兩個人的工資其實是一樣的10000,但是排名不一樣

接下來我們看一下rank,我們發現銷售部門那兩個工資相等的實並列第一了,然後下一個人直接第三了

接下來我們再看一下 dense_rank,工資相等的兩個人依然是排名相等的,但是下一個人還是第二

使用場景Top-N

Top-n 前面我們已經介紹過了,這裡就不再介紹了

計算連續

什麼是計算連續呢,這個名字有點不太合理,這裡舉個例子方便大家理解,加入我有個用戶訪問日誌表,那我想篩選出哪些超過連續7天都訪問的用戶,或者我想計算連續訪問天數最大的10位用戶

下面是一份測試數據用戶ID,訪問日期

1,2020-12-01
1,2020-12-02
1,2020-12-03
1,2020-12-04
1,2020-12-05
1,2020-12-06
1,2020-12-07
1,2020-12-08
1,2020-12-09
1,2020-12-10
2,2020-12-01
2,2020-12-02
2,2020-12-03
2,2020-12-04
2,2020-12-06
2,2020-12-07
2,2020-12-08

下面是我們的建表語句

CREATE TABLE ods.ods_user_log (
  id string,
  ctime string
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
load data local inpath '/Users/liuwenqiang/workspace/hive/user_log.txt' overwrite into table ods.ods_user_log;

現在我們分析一下這個問題,怎麼計算連續呢,計算肯定是針對同一個用戶的,然後我們可以按照用戶的訪問時間進行排序,然後我們用日期的數字減去對應的排序就會得到一個值,如果訪問時間是連續的話,我們就可以得到同一個值

select
    id,ctime,
    row_number(partition by id order by ctime ) as rn
from
    ods_user_log
;

這裡為了演示效果比較明顯,所以設計的數據有點特殊,大家可以看到對於id 是1的用戶,我們發現從12月1號到12月10號,我們的排名也依次是從1到10的,這個時候我們只要將日期變成對於的數字,然後減去對應的排名它是等於20201200的,這個時候我們只需要統計20201200的個數,這個個數就是連續登陸的天數,這裡我們就不把日期轉換成轉換成數字然後做減法了,我們直接使用日期去減。

select
    id,ctime,
    date_sub(cast(ctime as date),row_number() over(partition by id order by ctime)),
    row_number() over(partition by id order by ctime ) as rn
from
    ods_user_log
;

這下我再去統計每個用戶的相同日期有多少個即可,在我這裡因為是7天,所以我只需要計算出相同日期的個數大於等於7即可

select
    id,kt,count(1) as loginCnt
from (
    select
        id,ctime,
        date_sub(cast(ctime as date),row_number() over(partition by id order by ctime)) as kt,
        row_number() over(partition by id order by ctime ) as rn
    from
        ods_user_log
) tmp
group by
    id,kt
having
    count(1)>=7
;

我們嘗試著理解一下這個數據,它的意思就是用戶1 從(2020-11-30+1) 日開始,連續10天訪問了網站

這裡有個問題需要注意一下,那就是上面我造的數據就是每天一條的,如果每天如果有多條,那我們上面的代碼就不對了,所以這個時候我們不是需要使用dense_rank,大家注意理解一下,我們需要的是去重,大家注意理解一下

分組抽樣

其實抽樣這個東西大家都接觸過,隨機抽樣也接觸過,今天我們學習一下分組隨機抽樣,其實實現很簡單,我們使用row_number 在子窗口內隨機排序,然後抽出所需的樣本數據即可,我們還是用上面的數據,每個用戶隨機抽取三天登陸

select
    *
from (
    select
        id,ctime,
        row_number() over(partition by id order by rand() ) as rn
    from
        ods_user_log
) tmp
where rn<=3
;

總結

rank() 排序相同時會重複,總數不會變(會有間隙跳躍,數據不連續)

dense_rank() 排序相同時會重複,總數會減少(不會有間隙,數據連續的)

row_number() 會根據順序計算,不會重複不會減少

Row_number 函數常用的三種場景Top-N,計算連續,分組抽樣

相關焦點

  • Hive(七) ----函數
    函數內置函數-- 查看系統自帶函數 show functions;-- 顯示自帶函數的用法desc function upper;desc function extended upper;時間函數-- 當前前日期select current_date;select unix_timestamp();
  • 【點滴學習】JDH函數應用 row_number()
    應用場景:假設有一個分類圖書銷量表,要求應用HIVE函數取出每類銷量排名前3的圖書及銷量。解決思JDH代碼: SELECT category, sku_id, sales FROM ( SELECT * FROM book_sales
  • Hive窗口函數/分析函數詳解
    hive窗口函數/分析函數在sql中有一類函數叫做聚合函數,例如sum()、avg()、max()等等,這類函數可以將多行數據按照規則聚集為一行,一般來講聚集後的行數是要少於聚集前的行數的。但是有時我們想要既顯示聚集前的數據,又要顯示聚集後的數據,這時我們便引入了窗口函數。窗口函數又叫OLAP函數/分析函數,窗口函數兼具分組和排序功能。
  • Hive窗口函數總結與實踐
    order by子句會讓輸入的數據強制排序(窗口函數是SQL語句最後執行的函數,因此可以把SQL結果集想像成輸入數據)。Order By子句對於諸如Row_Number(),Lead(),LAG()等函數是必須的,因為如果數據無序,這些函數的結果就沒有任何意義。因此如果有了Order By子句,則Count(),Min()等計算出來的結果就沒有任何意義。
  • Hive窗口函數進階指南
    作為一名數據小哥,在寫SQL的漫漫路上,窗口函數猶如一把披荊斬棘的利劍,幫助作者解決了很多繁瑣複雜的需求,
  • HIVE 窗口函數實戰
    HIVE 窗口函數詳解中,我們介紹了hive窗口函數的定義和語法,本篇中我們根據例子來進行實戰。>排序窗口需求:求每個班級成績排名前三的學生。row_number()函數,唯一排序,不會生成排序相同的用戶示例和結果如下:可以看到,一班的學生三和學生四同樣為90分的學生,會按照不同的排名進行排名。rank()函數,不唯一排序,相同分數排名會相同,但後續排名會跳過。
  • 一文搞定Hive函數,建議收藏!
    導讀:工欲善其事必先利其器,hive是我們與大數據打交道的工具,所以我們需要熟練使用hive的一些函數,這樣後面的數據開發就得心應手啦。廢話不多說直接上乾貨。6、窗口函數7、條件函數1 數據準備首先我們創建一張收集用戶流量頁面的SQL表,同學們可以直接將其在mysql下創建:/*SQLyog Ultimate v12.09 (64 bit)MySQL
  • Hive常用的函數總結
    sqrt()函數表示對給定的數字取平方根,如下所示:hive (default)> SELECT Sqrt(5);OK_c02.23606797749979Time taken: 0.06 seconds, Fetched: 1 row(s)2、集合函數
  • Hive 窗口函數最全講解和實戰
    在不同的窗口執行的函數在深入研究Over字句之前,一定要注意:在SQL處理中,窗口函數都是最後一步執行,而且僅位於Order by子句之前可以想像成sql的輸出結果,就是窗口函數輸入的結果。主要的函數有:over()partition_byorder_bywindow函數row_number()rank()dense_rank()lag()lead()first_value()last_value()二、實例建立一個用戶消費表
  • hive函數
    :數學函數,字符函數,日期函數,條件函數,聚合函數。高級內置函數:行列轉換函數,分析性函數。自定義函數:udf。以上是小編自己整理分類的,網上也有很多不同分類的版本,下圖就是在別人博客中我覺得比較好的分類方法。
  • 鞏固SQL - 窗口函數&變量&數據透視圖
    但作為合格的一個數據分析師,sql的精通肯定是必不可少的,所以最近瘋狂刷sql題,同時也來總結下我以前比較少用的語法。(工作寫的是hive,為方便演示,本文章均使用Mysql8.0.16版本)一、窗口函數1、什麼是窗口函數窗口函數,也叫OLAP函數(Online Anallytical Processing,聯機分析處理),可以對資料庫數據進行實時分析處理。
  • hive常用函數
    3.窗口函數累計計算窗口函數•sum(A)over(partition by B order by C rows between D1 and D2)•avg(A)over(partition by B order by C rows between D1 and D2)    1.rows between unbounded preceding and current
  • hive sql 優化心得
    裡面的udtf,如果現有的函數滿足不了你的需求,可以開發一個udtf來實現自定義的行轉列操作。窗口函數是用於分析的一類函數,要理解窗口函數要先從聚合函數說起。通用的窗口函數可以用下面的語法來概括:Function() Over (Partition By Column1,Column2,Order By Column3);窗口函數分三類:聚合型窗口函數、分析型窗口函數、取值型窗口函數聚合型聚合型即SUM(), MIN(), MAX(),
  • hive之窗口函數和自定義函數
    demo就可以使用了介紹 而窗口函數在實際應用中也比較廣泛(據說強如clickhouse之後的計劃中也要支持窗口函數了)窗口函數,在進行分組聚合以後 , 我們還想操作集合以前的數據 使用到窗口函數可以這麼理解,在列記錄的後面安裝了一雙眼睛或者一個窗口來監視指定範圍內的行
  • HIVE 窗口函數詳解
    什麼是窗口函數窗口函數是 SQL 中一類特別的函數。和聚合函數相似,窗口函數的輸入也是多行記錄。不 同的是,聚合函數的作用於由 GROUP BY 子句聚合的組,而窗口函數則作用於一個窗口, 這裡,窗口是由一個 OVER 子句 定義的多行記錄。聚合函數對其所作用的每一組記錄輸 出一條結果,而窗口函數對其所作用的窗口中的每一行記錄輸出一條結果。一些聚合函 數,如 sum, max, min, avg,count 等也可以當作窗口函數使用。
  • 常用Hive函數的學習和總結
    今天來小結一下工作中經常會使用到的一些Hive函數。關於Hive函數的總結,網上早有十分全面的版本。參考:https://blog.csdn.net/doveyoung8/article/details/80014442。本文主要從最常用和實用的角度出發,說明幾個使用頻率較高的函數,更注重使用函數組合來解決實際問題而不局限於單個函數的使用。
  • SQL 中的 distinct 和 row_number() over() 的區別及用法
    3 row_number() over()在 SQL Server 資料庫中,為咱們提供了一個函數 row_number() 用於給資料庫表中的記錄進行標號,在使用的時候,其後還跟著一個函數 over(),而函數 over() 的作用是將表中的記錄進行分組和排序。
  • 通俗易懂的學會:SQL窗口函數
    <窗口函數>的位置,可以放以下兩種函數:1) 專用窗口函數,包括後面要講到的rank, dense_rank, row_number等專用窗口函數。2) 聚合函數,如sum. avg, count, max, min等因為窗口函數是對where或者group by子句處理後的結果進行操作,所以窗口函數原則上只能寫在select子句中。三.如何使用?接下來,就結合實例,給大家介紹幾種窗口函數的用法。
  • 大數據分析師工程師入門6-HIVE進階
    窗口函數要講HIVE進階,窗口函數不得不提,作者之前的文章《Hive窗口函數進階指南》已經很詳細地講解了這部分內容,為了省去大家點連結跳來跳去的麻煩,下面將其核心內容摘錄出來,如下所示。結合實際場景看看怎麼用窗口函數來解決問題。下面針對不同的使用場景,將窗口函數的使用呈現給大家。
  • SQL數據分析,窗口函數
    by時,沒有rows between則意味著窗口是從起始行到當前行,所以對不同國家進行累加求和操作。5、 不同國家平均金額SELECT *, AVG(payment) OVER() asavg_payment,AVG(payment) OVER(PARTITION by country) as country_ayg_payment from pay;使用avg聚合函數的用法與前面的聚合運算用法一致,PARTITION by同樣用來分組,這裡分組後求均值。