本文來自Spool的開發者博客,描述了Spool利用Redis的bitmaps相關的操做,進行網站活躍用戶統計工做。java
Redis支持對String類型的value進行基於二進制位的置位操做。經過將一個用戶的id對應value上的一位,經過對活躍用戶對應的位進行置位,就可以用一個value記錄全部活躍用戶的信息。以下圖所未,下圖中的bitmap有9個位被置爲1,表示這9個位上對應的用戶是今天的活躍用戶。其中第15位表示uid爲15的用戶,第一位表示uid爲0的用戶。(若是你的uid不是從1開始的,好比從100000開始,實際上你也能夠相應的用uid減去初始值來表示其位數,好比1000000用戶對應到bitmap的第一位)
redis
具體的代碼相似下面這樣:sql
redis.setbit(play:yyyy-mm-dd, user_id, 1)
這樣一次記錄的複雜度是O(1),在Redis中速度很是快。
而咱們經過天天換用一個不一樣的key來將天天的活躍用戶狀態記錄分開存。而且能夠經過一些與或運算計算出N天活躍用戶,和鏈接N天活躍用戶這樣的統計數據。
以下圖,第一行表示星期一的活躍用戶狀況,第二行表示週二的,以此類推。爲樣咱們經過對N天的活躍用戶記錄取並集操做,就能得出在N天內活躍過的用戶列表。
nosql
下面表格表示對應一天,一週,一個月統計時所花費的時間。網站
Period | Time (ms) |
---|---|
Daily | 50.2 |
Weekly | 392.0 |
Monthly | 1624.8 |
下面是具體的java代碼片段:ui
1.算出一天的活躍用戶數量spa
import redis.clients.jedis.Jedis; import java.util.BitSet; ... Jedis redis = new Jedis("localhost"); ... public int uniqueCount(String action, String date) { String key = action + ":" + date; BitSet users = BitSet.valueOf(redis.get(key.getBytes())); return users.cardinality(); }
2.計算某幾個內活躍用戶的數量(某一天活躍就算,因此是取並集)code
import redis.clients.jedis.Jedis; import java.util.BitSet; ... Jedis redis = new Jedis("localhost"); ... public int uniqueCount(String action, String... dates) { BitSet all = new BitSet(); for (String date : dates) { String key = action + ":" + date; BitSet users = BitSet.valueOf(redis.get(key.getBytes())); all.or(users); } return all.cardinality(); }
具體的用法還不少,好比你還能夠對獨特終端的用戶單獨記一個bitmap,這樣就能夠統計不一樣終端用戶的活躍狀況。有的同窗會說用set也能實現一樣的效果。但使用set在內存使用量上是會大不少的。blog