昨天群上有人發(fā)個阿里的面試題,題目描述大概如下:
數(shù)據(jù)源:用戶登錄表,只有倆個字段,uid和dt
試用HQL抽取出連續(xù)登錄了K天的用戶uid
第一個想法就是直接用一個UDF解決,按uid分組,把dt收集起來然后在UDF里面判斷是否滿足條件
SELECT
uid,
isExist(collect_set(dt), k) flag
FROM
table_name
GROUP
BY
uid
HAVING
flag
=
1
;
其中isExist的邏輯是判斷collect_set中是否存在k個連續(xù)的值
這種方法簡單明了,但是需要額外的寫一個UDF,對于不懂JAVA的來說確實比較麻煩
?
今天群里有個神人給出了一種新的解決思路,十分完美的解決了,下面是具體代碼
SELECT
uid,
MAX
(dt)
-
MIN
(dt) diff, COLLECT_set (dt)
FROM
(
SELECT
a.uid, a.dt, dt
-
rn num
FROM
(
SELECT
uid, dt, row_number ()
over
(PARTITION
BY
uid
ORDER
BY
dt) rn
FROM
table_name
GROUP
BY
uid, dt) a) a
GROUP
BY
uid, num
該思路首先利用窗口函數(shù)以uid分組然后按照dt排序給出每個dt在排序中的位置,然后用求出dt與位置的差(記為num)
最后按照uid和num做一個聚合,容易發(fā)現(xiàn)同一個num組內(nèi)的dt是連續(xù)的值
然后直接計數(shù)(count(*))就可以得出結(jié)果了
上面的代碼只是為了更加方便看到輸出的結(jié)果正確性,輸出結(jié)果如下:
UID DIFF DT_ARRAY
1043736
3.0
{
20140815
20140814
20140813
20140812
}
1043736
0.0
{
20140818
}
1043736
1.0
{
20140821
20140820
}
1043844
0.0
{
20140814
}
1044090
1.0
{
20140812
20140811
}
1044090
2.0
{
20140816
20140815
20140817
}
1044090
0.0
{
20140821
}
1044264
0.0
{
20140810
}
1044264
3.0
{
20140815
20140814
20140813
20140812
}
1044264
5.0
{
20140821
20140820
20140822
20140819
20140817
20140818
}
結(jié)果中uid =?1043736 的一共登錄了7天,其中可以拆分成三個連續(xù)的登錄模塊,分別是連續(xù)登錄1天、2天和4天
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

