位运算实现用户留存率
統計留存率之前先弄清一下留存率的概念,百度百科中是這么說的:
用戶在某段時間內開始使用應用,經過一段時間后,仍然繼續使用應用的被認作是留存;
這部分用戶占當時新增用戶的比例即是留存率,會按照每隔1單位時間(例日、周、月)來進行統計。
顧名思義,留存指的就是“有多少用戶留下來了”。留存用戶和留存率體現了應用的質量和保留用戶的能力。
簡單點說,第一天新增加了100個用戶,第二天這100個人有50個還有登錄,第三天這100個人還有30個有登錄。。。依次類推 那次日留存率為50%,三日留存為30% 。
在統計系統中經常需要統計用戶留存率,這里整理下用戶留存率統計的幾種實現方式。
1、通過最后登錄時間實現
有一張唯一表來記錄新增用戶,這張表至少包含這三個字段: uid, reg_time, last_visited_time。用戶每次訪問后更新最后訪問時間(last_visited_time),假設3.6號新注冊100個用戶,需要統計次日留存,則在3.8號凌晨統計reg_time為3.6并且last_visited_time為3.7號即可,參考SQL:
SELECT COUNT(*) FROM TBL_NAME WHERE DATE(reg_time) = '2014-03-06' AND DATE(last_visited_time) = '2014-03-07'
實現起來很簡單,但問題也很明顯,如果恰好這些用戶0點有訪問,且先一步更新了訪問時間,留存率則記錄不到了,這個對整個的結果偏差不會太大,先忽略。有一個更明顯的問題就是無法重復統計,如果腳本出錯或者需要重新統計則無法實現。當然好處也有,就是統計方便,同時也方便新增N日留存。
2、通過建立獨立的字段實現
獨立的字段可以這么設計,uid,reg_time,day_2,day_3,day_4…等等,當用戶第二天有訪問時更新day_2的字段為1,第三日訪問更新day_3為1,該系列字段默認為0。同樣的統計次日留存,則SQL應該是這樣子:
SELECT COUNT(*) FROM TBL_NAME WHERE DATE(reg_time) = '2014-03-06' AND day_2 = 1
該方法可以重復統計了,但又不方便擴展了,如果當前沒有考慮到15天流程,則需要修改表結構,新增day_15才行。
3、通過位運算實現
上面的數據表中記錄的值就是很多的0和1,可以用這些二進制的0和1來表示當天是否有訪問過,1表示有訪問過,0表示未訪問過。設計表中有這幾個字段,uid,reg_time,retension,假設留存用retention記錄,則
第一天訪問 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 對應十進制的1,retention記錄為1
第二天訪問 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 第二天有訪問后retention更新為3
第四天訪問 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 第三天沒有訪問,第四天訪問后rentention更新為11
依次類推,接下來就是計算該天的留存,以次日留存為例。將次日的數據與第2位為1其他位為0的值做按位與操作
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 & 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
按位與是將都為1的設置為1,如果用整數來表示,求次日留存是 3 & 2 ,如果結果為2則表示次日有訪問過,如果不為2結果為0則說明沒有訪問過。所以求第N天的sql應該是(N表示第N天留存,如第3天用第3位來表示就是2的2次方):
SELECT COUNT(*) FROM TBL_NAME WHERE DATE(reg_time) = 'XXXX-XX-XX' AND retention & 2^(N-1)
當然這里的第幾天實際表示第幾日留存可以自己定,如果第10位表示30日留存,則將retention與2^9求按位與即可求得30日留存。
這里解決了讀的問題,還有寫的問題,首次注冊時值為0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ,第二天有訪問則將前一天的值與第二位為1其他位為0的做按位或操作即可,按位或是將其中任何一個為 1 的位設為 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
第三天沒有訪問,第四天訪問則是
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 | 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 = 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1
用SQL來表示就是(N表示第N天訪問)
UPDATE TBL_NAME SET retention = retention | 2^(N-1) WHERE uid = 'XX'
而且該更新操作在當天是可以重復操作的,因為按位或只需要有一個為1即可,第2天第一次更新1 | 2 = 3,第二次更新3 | 2 = 3。可見值是相同的。 聽到這種方案后也懷疑效率問題,在1000w數據中統計速度與reg_time中索引時間差不多,所以問題不大;一個整形4個字節32位,可以表示32個不同的留存,整形不夠也可以用長整型8個字節的。總體看來該方法可擴展,可重新統計,所以可行。
位運算之前只在權限中見過,這里用法也是一種不錯的方式,期待更多的思考,下面是位運算的基本操作:
總結
以上是生活随笔為你收集整理的位运算实现用户留存率的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 合军聚众和整装待发哪个好
- 下一篇: 不再迷惑,无值和 NULL 值