需求
有日誌如下,寫出代碼求得所有用戶和活躍用戶的總數及平均年齡。(活躍用戶指連續兩天都有訪問記錄的用戶)
日期 用戶 年齡
dt string,user_id string,age int
2019-02-11,test_1,23
2019-02-11,test_2,19
2019-02-11,test_3,39
2019-02-11,test_1,23
2019-02-11,test_3,39
2019-02-11,test_1,23
2019-02-12,test_2,19
2019-02-13,test_1,23
2019-02-15,test_2,19
2019-02-16,test_2,19
create table user_age(dt string,user_id string,age int)row format delimited fields terminated by ‘,’;
分析:
相信所有用戶的相關指標並不難求,關鍵在於活躍用戶的求取。這裏關於活躍用戶的定義是連續兩天有訪問記錄。可能有的小夥伴會想到用lag或lead函數,這裏的指標是連續兩天確實可以。但如果活躍定義指標業務口徑爲連續7天、30天有訪問記錄呢?
在此換一種思路,基於row_number對dt字段進行自然排序(默認升序,注意在此之前先進行數據去重)獲得dtrk。而後將dt減去dtrk得到日期diff。結果如下:
基於等差數列原理,不難發現連續活躍的日期下會得到相同的diff。而後基於user_id,diff進行聚合即可得到用戶的連續活躍天數
而後取出連續天數seqactive最大值,並進行過濾即得到目標。爲了方便後續操作,在此添加了狀態列state。
最後進行union all兩表(全部用戶、活躍用戶相關指標)
代碼如下:
求獲取全部用戶(連續兩天有訪問記錄)相關指標,採用等等差數列原理
1、去重
select user_id,age,dt from user_age group by user_id,age,dt; =>t1
2、求所有用戶的平均年齡
select 'all' state ,sum(1) userCount,avg(age) avgAge from
t1; =>tt
求獲取活躍用戶(連續兩天有訪問記錄)相關指標,採用等等差數列原理
1、按照user_id進行分組,按訪問時間進行排序row_number
select user_id,dt, row_number() over(partition by user_id order by dt) dtrk ,age from
t1; =>t2
2、計算日期與rk的差值
select user_id,dt,dtrk,date_sub(dt,dtrk) as diff ,age from
t2; =>t3
3、按差值進行聚合統計,日期差值相同的即爲連續活躍的記錄
select user_id,age ,count(*) seqActive from
t3
group by user_id,age,diff; =>t4
4、取出活躍天數最大值,去重
select user_id,age ,max(seqActive) seqActiveMax from
t4
group by user_id,age; =>t5
5、過濾出活躍用戶(最大活躍天數大於2的用戶),並計算活躍用戶總數以及平均年齡,添加狀態列
select 'active' state , sum(1) actuserCount,avg(age) actavgAge from
t5
where seqActiveMax >=2; =>t6
6、合併兩表(最終結果)
select *from
(select 'all' state , sum(1) userCount,avg(age) avgAge from
(select user_id,age from user_age group by user_id,age)t1)tt
union all
select 'active' state , sum(1) actuserCount,avg(age) actavgAge from
(select user_id,age ,max(seqActive) seqActiveMax from
(select user_id,age ,count(*) seqActive from
(select user_id,dt,dtrk,date_sub(dt,dtrk) as diff ,age from
(select user_id,dt, row_number() over(partition by user_id order by dt) dtrk ,age from
(select user_id,age,dt from user_age group by user_id,age,dt)t1)t2)t3
group by user_id,age,diff)t4
group by user_id,age)t5
where seqActiveMax >=2 ;