Hive實戰—時間滑動窗口計算

關注公衆號:大數據技術派,回覆: 資料,領取1024G資料。

時間滑動計算

今天遇到一個需求大致是這樣的,我們有一個業務涉及到用戶打卡,用戶可以一天多次打卡,我們希望計算出7天內打卡8次以上,且打卡時間分佈在4天以上的時間,當然這只是個例子,我們具體解釋一下這個需求

  1. 用戶一天可以打卡多次,所以要求打卡必須分佈在4天以上;
  2. 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的通用方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章