昨天群上有人發個阿里的面試題,題目描述大概如下:
數據源:用戶登錄表,只有倆個字段,uid和dt
試用HQL抽取出連續登錄了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個連續的值
這種方法簡單明了,但是需要額外的寫一個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
該思路首先利用窗口函數以uid分組然后按照dt排序給出每個dt在排序中的位置,然后用求出dt與位置的差(記為num)
最后按照uid和num做一個聚合,容易發現同一個num組內的dt是連續的值
然后直接計數(count(*))就可以得出結果了
上面的代碼只是為了更加方便看到輸出的結果正確性,輸出結果如下:
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 }
結果中uid =?1043736 的一共登錄了7天,其中可以拆分成三個連續的登錄模塊,分別是連續登錄1天、2天和4天
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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