Hive實戰—時間滑動窗口計算
關注公眾號:
大數據技術派
,回復:資料
,領取1024G
資料。
時間滑動計算
今天遇到一個需求大致是這樣的,我們有一個業務涉及到用戶打卡,用戶可以一天多次打卡,我們希望計算出7天內打卡8次以上,且打卡時間分布在4天以上的時間,當然這只是個例子,我們具體解釋一下這個需求
- 用戶一天可以打卡多次,所以要求打卡必須分布在4天以上;
- 7天不是一個自然周,而是某一天和接下來的6天,也就是說時間是是滑動的,窗口大小是7步長是1,說白了就是窗口計算;
其實說到這裡你就想到了窗口函數,雖然這是一個窗口;但是hive
卻沒有相應的窗口函數可以計算,接下來我們看一下怎麼實現這個邏輯
外部調用實現時間循環
我們可以先寫這樣的一個SQL,就計算每個人在特定時間內是否滿足我們的條件,我們先計算出每個人每天的打卡次數,例如這裡我們的時間限制是’20210701′ 到’20210707′
select
b.union_id,to_date(ds,'yyyymmdd') as dt,count(1) as cnt
from
ods_la_daily_record_di b
where
-- 驅動表的時間限制
b.ds>='${bizdate}'
and b.ds<=${bizdate2}'
group by
b.union_id,ds
然後我們再判斷這個時間端內,用戶的打卡情況是否滿足我們的條件
select
union_id,count(1) as 打卡天數, sum(cnt) as 打卡次數
from
(
select
b.union_id,ds,count(1) as cnt
from
ods_la_daily_record_di b
where
-- 驅動表的時間限制
b.ds>='${bizdate}'
and b.ds<='${bizdate2}'
group by
b.union_id,ds
)
group by
union_id
having
-- 時間分布在4天以上
count(1)>=4
-- 打卡次數在8次以上
and sum(cnt)>=8
;
這樣我們就算出來我們需要的數據,接下來我們只需要用其他語言調用這個SQL ,傳入不同的時間參數就可以了,利用程式語言實現時間的滑動,例如第一次傳入’20210701-20210707′ 第二次傳入’20210702-20210708′ 以此傳入即可。
雖然可以實現,但是不好,因為我們還需要其他語言的調用,其實我們知道在SQL裡面的關聯其實就是通過循環實現的,那我們即然能通過循環實現這個需求,我們能不能通過關聯實現這個需求呢
自關聯實現滑動時間窗口
其實我們只要讓用戶某一天的數據和他接下來的6天的數據關聯,然後按照這一天的數據進行匯總然後判斷時候滿足我們的條件即可,如果滿足了條件,那麼用戶這一天的數據就是滿足我們的需求的,也就是說這個用戶是滿足我們的需求的。
with tmp as(
-- 每個人每天打卡的次數
select
b.union_id,to_date(ds,'yyyymmdd') as dt,count(1) as cnt
from
ods_la_daily_record_di b
where
-- 驅動表的時間限制
b.ds>='${bizdate}'
group by
b.union_id,ds
)
select
union_id
from (
-- 滿足條件的(用戶-天)
select
a.union_id,a.dt,sum(b.cnt) as 打卡次數,count(1) as 打卡天數
from
tmp a
inner join
tmp b
on
a.union_id=b.union_id
and DATEDIFF(b.dt,a.dt)>=0
and DATEDIFF(b.dt,a.dt)<=6
group by
a.union_id,a.dt
having
-- 次數限制
sum(b.cnt)>=8
-- 天數限制
and count(1)>=4
)group by
-- 對用戶去重
union_id
;
這裡有一個問題需要注意一下,那就是我們滿足條件sum(b.cnt)>=8 and count(1)>=4
的是用戶某一天的數據,也就是說我們的維度是union_id-天
,所以我們需要對這個數據按照用戶為度進行去重。
擴展基於自然周的的滾動時間窗口計算
我們這裡思考一個問題,那就是我們知道很多時候我們的計算其實是圍繞著自然周的,雖然我們上面的計算不是自然周,那假設我們如果要求我們的計算是自然周呢,那這個時候我們應該怎麼計算呢,其實我們數倉里有一種很表叫做時間維表,我們利用時間維表可以很方便的計算時間相關的東西,如果你沒有的話建議去網上找一份,或者自己生成一份,因為使用起來很方便。
因為這個表的欄位很多,這裡我們截取了一部分放到這裡了,下面我們看一下怎麼使用時間維表進行計算。
select
UNION_ID,time_weeknum,count(1) as 打卡天數, sum(cnt) as 打卡次數
from(
select
b.union_id,ds,count(1) as cnt
from
ods_la_daily_record_di b
where
-- 驅動表的時間限制
b.ds>='${bizdate}'
and b.ds<='${bizdate2}'
group by
b.union_id,ds
) a
left join
dim_date_time b
on
a.ds=b.time_date
group by
-- 周的標識
UNION_ID,time_weeknum
HAVING
-- 時間分布在4天以上
count(1)>=4
-- 打卡次數在8次以上
and sum(cnt)>=8
;
這裡我們就基於每個自然周算出了滿足條件的人,當然我們還是要針對用戶去重
總結
我們看到自關聯其實可以達到滑動的效果,當然不僅僅體現在時間上,就像窗口除了時間窗口還是有基於個數的窗口,我們要在遇到類似問題的時候就可以選擇這樣的解決方案。
時間維表很重要,可以簡化我們的計算,如果沒有的話,需要創建一個。
交流群
加我微信:ddxygq
,回復加群
,我拉你進技術交流群。
猜你喜歡
數倉建模—指標體系
數倉建模—寬表的設計
Spark SQL知識點與實戰
Hive計算最大連續登陸天數
Flink計算pv和uv的通用方法