大家有沒有想過如何統計活躍用戶數量?如果是自己做,那該怎麼做?
這裡思考一分鐘,後面我將分享一下如何使用 redis 中的位圖來統計活躍用戶數。
正文
什麼是位圖 ?
位圖(bitmap)是二進制的 byte 數組 ,也可以簡單理解成是一個普通字符串。它將二進制數據存儲在 byte 數組中以達到存儲數據的作用。
圖 1.1
如何使用位圖 ?
理清概念
在解釋什麼是位圖的時候說過,位圖可以理解成是一個普通字符串, 那麼我們為什麼要用位圖而不是字符串呢 ?
下面是在 redis 中存儲字符串的一個示意圖
圖 2.1
如圖,存儲字符串是將字符串二進制數組的形式存儲在 redis 中,位圖可以直接對 二進制的數組操作, 位圖的優勢在於可以用 0 和 1來存儲布爾值,這大大降低了我們的存儲空間消耗 。由於這個特性,我們 用位圖來記錄簽到信息,記錄活躍用戶等 ,可以達到節省空間的能力(後面會有介紹)。
那我們如何對二進制的數組進行操作呢?
基本存取
setbit | getbit
上文說的二進制數組我們可以對它做 添加、查找及修改 的功能
如何進行添加和查找呢?
<code>setbit [keyName] [offset] [value]/<code>
offset:偏移量,指的是數組的下標; value: 數據, 只能是 0 和 1。
這條命令既可以添加數據也可以修改數據。
如何進行查找呢 ?
<code>getbit [keyName] [offset]/<code>
offset:偏移量,指的是數組的下標。這裡,除了設置 value 為 1 的 offset, 查詢其他的都返回 0
補充:上面說了位圖可以理解成字符串,那麼它們之間可以互相操作嗎?
圖 2.2
請對照上圖,我們一起完成下面的探究:
- 以字符串存儲,可以通過 getbit 命令獲取到值嗎?我們可以結合查詢和圖片所示的 offset 及所對應的值來驗證> set str hi OK > getbit str 0 (integer) 0 > getbit str 4 (integer) 1 > getbit str 7 (integer) 0 > getbit str 15 (integer) 1 複製代碼結論:可以的
- 以字符串存儲,可以通過 settbit 修改值嗎?我們可以試著將 offset 7 對應的 value 改成 1, 如果成功了,h 字符應該變成 i> setbit str 7 1 (integer) 0 > get str "ii" 複製代碼結論:可以
- 用 setbit 存儲字符串的二進制數據,可以通過 get 獲取字符串嗎?我們將 字符 h 的二進制存入位圖,看可以能通過 get 獲取> setbit bitmap 0 0 (integer) 0 > setbit bitmap 1 1 (integer) 0 > setbit bitmap 2 1 (integer) 0 > setbit bitmap 3 0 (integer) 0 > setbit bitmap 4 1 (integer) 0 > setbit bitmap 5 0 (integer) 0 > setbit bitmap 6 0 (integer) 0 > setbit bitmap 7 0 (integer) 0 > get bitmap "h" 複製代碼結論:可以
上面介紹了位圖的基本概念和使用,通過一系列的探究希望能幫助大家更好的理解位圖
那麼,如何將位圖應用的項目中呢?
統計和查找
bitcount | bitpos
bitcount 是用來查找 1 出現的次數,既可以對位圖使用也可以對字符串使用 ,用法如下:
<code>bitcount [keyName] [startWith] [endWith]/<code>
注意:這裡的 startWith 和 endWith 不是二進制數組的下標(offset)
這裡的 startWith 和 endWith 可以理解成是字符串的下標,一個字符串對應 8 位二進制數據;它們相當於是截取字符串,如 s= "hi" , s[0:0] = "h" , 它所對應的二進制數組的下標是 0,7,以此類推。
其實這裡不好解釋,先來帶代碼,可以結合著上面的 圖 2.2 看一下,大家後面可以在領悟一下
<code>> set str hi
> bitcount str 0 0
(integer) 4
> bitcount str 0 1
(integer) 8
> bitcount str
(integer) 8/<code>
注意:startWith 和 endWith 不設置的時候默認全部範圍
應用場景: 統計活躍用戶的數量
bitpos 用來查找指定範圍內出現的第一個 0 或 1 ,用法如下:
<code>bitpos [keyName] [bit] [start] [end]/<code>
bit: 要找的 0 或者 1, start 和 end 同上面的 startWith 和 endWith
應用場景: 獲取第一次簽到和第一次未簽到的時間
應用場景
上面大致說了 2 個應用場景:
- 統計活躍用戶的數量
- 獲取第一次簽到和第一次未簽到的時間
我在這裡稍微介紹一下思路,然後附上一個 統計活躍用戶的數量 可供參考
統計活躍用戶的數量
- 將位圖的 keyName 設置成需要統計的 行為和時間範圍 [ation:date], 如: login:2020-3
- 將用戶對應到位圖中的 offset , 如 id 對應二進制數組的下標, id 為 int
- 簽到成功使用 setbit 將對應的 offset 設置成 1
- 使用 bitcount 統計某個 行為和時間範圍 的活躍人數,如 bitcount login:2020-3
Demo: DailyActiveUsers
獲取第一次簽到和第一次未簽到的時間
- 將位圖的 keyName 設置成需要統計的 行為和時間範圍和對象 [ation: date:person], 如: login:2020-3:Tom
- 將日期對應到位圖中的 offset , 如 1號對應二進制數組的下標 0, 2 號為 1
- 簽到成功使用 setbit 將對應的 offset 設置成 1
- 使用 bitpos 統計某個 行為和時間範圍和對象 的簽到情況,如 bitpos login:2020-3:Tom 1
閱讀更多 sandag 的文章