窗口函数_LAG()与LEAD() 详解
轉(zhuǎn)載自:Hive 窗口函數(shù)lead 和 lag(39)
補充:HIVE_HIVE函數(shù)_窗口函數(shù)_LAG()/LEAD() 詳解
lead 和 lag
前面我們學習的first_value和last_value 取的是排序后的數(shù)據(jù)截止當前行的第一行數(shù)據(jù)和最后一行數(shù)據(jù)
Lag和Lead分析函數(shù)可以在一次查詢中取出當前行后N行和前N行的數(shù)據(jù),雖然可以不用排序,但是往往只有在排序的場景下取前面或者后面N 行數(shù)據(jù)才有意義
這種操作可以代替表的自聯(lián)接,并且LAG和LEAD有更高的效率。
Lag/Lead(col,n,DEFAULT) 用于統(tǒng)計窗口內(nèi)當前行往前或者往后第n行值
- 第一個參數(shù)為列名,
- 第二個參數(shù)為往后/前第n行(可選,默認為1),
- 第三個參數(shù)為默認值(當往上第n行為NULL時候,取默認值,如不指定,則為NULL)
需要注意的是lag 取得是當前行之前的數(shù)據(jù),lead 取的實當前行之后的數(shù)據(jù)
測試數(shù)據(jù)
我們有這樣一個文本user_access_log.txt,里面記錄了用戶對頁面的訪問情況id,ctime,url 分別代表了用戶ID,訪問時間和訪問的頁面的URL
Peter 2015-10-12?01:10:00 url1 Peter 2015-10-12?01:15:10 url2 Peter 2015-10-12?01:16:40 url3 Peter 2015-10-12?02:13:00 url4 Peter 2015-10-12?03:14:30 url5 Marry 2015-11-12?01:10:00 url1 Marry 2015-11-12?01:15:10 url2 Marry 2015-11-12?01:16:40 url3 Marry 2015-11-12?02:13:00 url4 Marry 2015-11-12?03:14:30 url5數(shù)據(jù)說明:Peter 2015-10-12 01:10:00 url1 ? ,表示Peter在2015-10-12 01:10:00進入了網(wǎng)頁url1,即記錄的是進入網(wǎng)頁的時間。
從例子中學習lead 和 lag
計算當前用戶的第一次訪問時間以及當前訪問時間的上一次訪問時間和下一次訪問時間
從描述我們知道了分區(qū)的條件或者子窗口的定義條件是用戶本身,從我們前面的學習中我們知道了第一次訪問時間我們可以使用first_value 計算,下面我們看一下這個需求如何實現(xiàn)
selectuserid,url,ctime,first_value(ctime) over(partition by userid order by ctime) as first_ctime,lag(ctime,1) over(partition by userid order by ctime) as lag_ctime,lead(ctime,1) over(partition by userid order by ctime) as lead_ctime from ods_user_log;這里我們也對這個結果簡單分析一下,對于第一行數(shù)據(jù)它是沒有l(wèi)ag_ctime的,也就是沒有上一次訪問時間,因為它是第一次訪問,對于lead_ctime也就是下一次訪問時間2015-11-12 01:15:10
計算用戶在每個頁面上的停留時長
用戶Peter在瀏覽網(wǎng)頁,在某個時刻,Peter點進了某個頁面,過一段時間后,Peter又進入了另外一個頁面,如此反復,那怎么去統(tǒng)計Peter在某個特定網(wǎng)頁的停留時間呢,又或是怎么統(tǒng)計某個網(wǎng)頁用戶停留的總時間呢?
要計算Peter在頁面url1停留的時間,需要用進入頁面url2的時間,減去進入url1的時間,即2015-10-12 01:15:10這個時間既是離開頁面url1的時間,也是開始進入頁面url2的時間。所以我們需要先獲取用戶在某個頁面停留的起始與結束時間
selectuserid,url,ctime as startTime, lead(ctime,1) over(partition by userid order by ctime) as leaveTime from ods_user_log;有了進入時間和離開時間我們就很容易計算出用戶在特定頁面上的停留時間,只需要用離開時間減去進入時間即可
selectuserid,url,ctime as startTime,lead(ctime,1) over(partition by userid order by ctime) as leaveTime,unix_timestamp(lead(ctime,1) over(partition by userid order by ctime) ) -unix_timestamp(ctime) as stayTime from ods_user_log;大家考慮一個問題如果沒有l(wèi)ag和lead這樣的函數(shù),我們該如何實現(xiàn)這個需求呢,我們可以借助自關聯(lián)來實現(xiàn),但是這個自關聯(lián)就有很多種是想方式了,這里我借助row_number 來實現(xiàn)一種
with a as (select userid,url,ctime as startTime,row_number() over (partition by userid order by ctime ) as rnfromods_user_log ) select a1.userid userid,a1.startTime startTime,a2.startTime leaveTime,unix_timestamp(a2.startTime )-unix_timestamp(a1.startTime ) as stayTimefrom a a1 inner join a a2 on a1.userid=a2.useridand (a2.rn-a1.rn=1) ;這里我們主要是使用 (a2.rn-a1.rn=1) 的條件找出了用戶進入頁面和離開頁面的時間
使用場景
lead 和 lag 的使用場景其實是比較多的,尤其我們在計算需要自關聯(lián)的這種場景下,如果合理使用頭是可以很好的提高我們程序的性能和簡化我們的寫法,下面我們再看一個例子
有個日志表中記錄了商戶費率變化狀態(tài)的所有信息用戶ID,費率,時間,現(xiàn)在有個需求,要取出按照時間軸順序,發(fā)生了費率變化的數(shù)據(jù)行,輸出數(shù)據(jù)格式商戶ID,當前時間,變化時間,原始費率,變化后的費率
100,0.1,2016-03-02 100,0.1,2016-02-02 100,0.2,2016-03-05 100,0.2,2016-03-06 100,0.3,2016-03-07 100,0.1,2016-03-09 100,0.1,2016-03-10 100,0.1,2016-03-10 200,0.1,2016-03-10 200,0.1,2016-02-02 200,0.2,2016-03-05 200,0.2,2016-03-06 200,0.3,2016-03-07 200,0.1,2016-03-09 200,0.1,2016-03-10 200,0.1,2016-03-10現(xiàn)在我們開始建表
create table ods_user_rate_log(userid string,rate double,ctime string ) row format delimited fields terminated by ','; LOAD DATA LOCAL INPATH '/Users/liuwenqiang/workspace/hive/ods_user_rate_log.txt' OVERWRITE INTO TABLE ods_user_rate_log;現(xiàn)在們分析一下,首先我們是單獨計每個商戶的,所以我們的子窗口定義條件就是用戶ID,然后我們跟蹤的是費率的隨時間的變化所以我們是要按照時間排序,最后我們需要的費率發(fā)生了變化的數(shù)據(jù),所以我們需要比較一下原始費率和下一次費率
第一步:獲取當前費率和下一次的費率
select userid,ctime,rate, lead(rate,1) over (partition by userid order by ctime) new_rate from ods_user_rate_log;第二步:找出費率不同的記錄然后返回,需要注意的是,我們還需要需要獲取到發(fā)生變化的時間
select * from(select userid,ctime,lead(ctime,1) over (partition by userid order by ctime) new_date,rate, lead(rate, 1) over (partition by userid order by ctime) new_rate from ods_user_rate_log) tmp where rate!=new_rate;總結
lag和lead 主要用來計算當前行的前后N 行的這種場景,一般情況下我們會對數(shù)據(jù)進行排序,因為只有在有序的情況下,前面多少行和后面多少行才有意義
lag和lead 可以用在某些場景下代替自關聯(lián)的寫法
總結
以上是生活随笔為你收集整理的窗口函数_LAG()与LEAD() 详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常用找图网
- 下一篇: 《边缘云计算技术及标准化白皮书》