使用Redis的bitmaps統計活躍用戶

首先我們看一個場景:一個網站,需要統計一周內連續登陸的用戶,以及一個月內登陸過的用戶。

如果用傳統的數據庫如Mysql來實現的話,很難做到。但如果用redis來做的話,就很簡便。Redis的集合類型和Bitmap類型都可以很容易的做到。今天,我們主要來談談如何用Bitmaps來實現統計活躍用戶的功能。

Bitmaps

在計算機系統中,最小的信息單位是字節,1個字節等于8位,每一位都只可能是0或1(計算機只認識這兩個數)。使用Bitmaps可以直接對位進行操作。

可以把bigmaps看做一個數組,數組里每一位只可能是0或者1,數組的下標在這里看做偏移量。

下面我們來介紹幾個和Bitmaps相關的命令:

setbit

setbit key offset value:給對應的位設置值

比如今天有用戶3、8、23、32訪問了網站,則

setbit?user:view:2020-5-17?3?1 setbit?user:view:2020-5-17?8?1 setbit?user:view:2020-5-17?23?1 setbit?user:view:2020-5-17?32?1

開發提示:很多應用id都不是從1開始,有許多是從指定數字開始的,比如1001、10001開始。對于這些,我們在設置的時候可以先減去初始值,防止浪費空間

getbit

getbit key offset 獲取指定位的值

如果我想知道今天8號用戶和45號用戶是否登錄過,則

127.0.0.1:6379>?getbit?user:view:2020-5-17?8 (integer)?1 127.0.0.1:6379>?getbit?user:view:2020-5-17?45 (integer)?0

可以看到8號用戶今天登錄過,但是45號用戶今天還沒有登錄。

bitcount

bitcount key [start] [end] 獲取指定范圍為1的個數

我想知道今天有多少用戶登陸過了,則

127.0.0.1:6379>?bitcount?user:view:2020-5-17 (integer)?4

Bitmaps間的操作

bitop op destkey key [key …]

bitop命令可以對多個bitmaps做交集(and)、并集(or)、非(not)、異或(xor),并將操作結果存放在destkey中。

如果想知道連續三天都登陸過的用戶,即5月17日、18日、19日都登陸的用戶數量。

這三天登陸情況如下:

  • 5月17日3、8、23、32用戶登陸過

  • 5月18日3、23、43、54號用戶登陸過

  • 5月19日3、5、23、 32、56、78號用戶登陸過

127.0.0.1:6379>?bitop?and?three:and?user:view:2020-5-17?user:view:2020-5-18?user:view:2020-5-19 127.0.0.1:6379>?bitcount?three:and (integer)?2

如果想知道,這三天有多少用戶登陸過。

127.0.0.1:6379>?bitop?or?three:or?user:view:2020-5-17?user:view:2020-5-18?user:view:2020-5-19 (integer)?10 127.0.0.1:6379>?bitcount?three:or (integer)?9

可以看到,這三天共有9位用戶登陸過。

實戰

講完上面所講知識后,我們就可以來完成想要的需求:需要統計一周內連續登陸的用戶,以及一個月內登陸過的用戶。

首先模擬用戶30天內登陸情況,偽代碼如下:

for?($i?=?0;?$i?setBit($key,?$userId,?1); }

獲取一周內都登陸的用戶,當然我們不會一次性全部取,而是想分頁那樣,一次取一定數量的,偽代碼如下:

for?($i?=?1;?$i?bitOp('and',?'week_logined',?$key); ????}?else?{ ????????$redis->bitOp('and',?'week_logined',?'week_logined',?$key); ????} } ? //?獲取前50個用戶 $userIds?=?[]; for?($i=1;?$igetBit('week_logined',?$i); ????$ret?&&?$userIds[]?=?$i; ? ????if?(count($userIds)?>=50)?break; }

這里面有一個注意點,也是易錯點,在bitop時候,第一次的時候,因為week_logined還不存在,所以進行op的鍵只有一個。當從第二次開始時候,進行op的鍵就為2個了。

獲取一個月內登陸的用戶,思路基本和上面一樣,只是將and改為or

for?($i?=?1;?$i?bitOp('or',?'month_loginOnce',?'month_loginOnce',?$key); } ? //?獲取一個月內登陸過的用戶 $userIds?=?[]; for?($i=1;?$igetBit('month_loginOnce',?$i); ????$ret?&&?$userIds[]?=?$i; }

可以看到,在進行or的時候和and還是有些區別的。or的時候,無需對第一次進行判斷。個中緣由,大家自己體會體會。

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享