昨天群上有人發(fā)個(gè)阿里的面試題,題目描述大概如下:
數(shù)據(jù)源:用戶(hù)登錄表,只有倆個(gè)字段,uid和dt
試用HQL抽取出連續(xù)登錄了K天的用戶(hù)uid
第一個(gè)想法就是直接用一個(gè)UDF解決,按uid分組,把dt收集起來(lái)然后在UDF里面判斷是否滿足條件
SELECT uid, isExist(collect_set(dt), k) flag FROM table_name GROUP BY uid HAVING flag = 1 ;
其中isExist的邏輯是判斷collect_set中是否存在k個(gè)連續(xù)的值
這種方法簡(jiǎn)單明了,但是需要額外的寫(xiě)一個(gè)UDF,對(duì)于不懂JAVA的來(lái)說(shuō)確實(shí)比較麻煩
?
今天群里有個(gè)神人給出了一種新的解決思路,十分完美的解決了,下面是具體代碼
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ù)以u(píng)id分組然后按照dt排序給出每個(gè)dt在排序中的位置,然后用求出dt與位置的差(記為num)
最后按照uid和num做一個(gè)聚合,容易發(fā)現(xiàn)同一個(gè)num組內(nèi)的dt是連續(xù)的值
然后直接計(jì)數(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天,其中可以拆分成三個(gè)連續(xù)的登錄模塊,分別是連續(xù)登錄1天、2天和4天
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
