# BITCOUNT
**BITCOUNT key [start] [end]**
計算給定字符串中,被設置為 `1` 的比特位的數量。
一般情況下,給定的整個字符串都會被進行計數,通過指定額外的 `start` 或 `end` 參數,可以讓計數只在特定的位上進行。
`start` 和 `end` 參數的設置和 [_GETRANGE_](getrange.html#getrange) 命令類似,都可以使用負數值: 比如 `-1` 表示最后一個字節, `-2` 表示倒數第二個字節,以此類推。
不存在的 `key` 被當成是空字符串來處理,因此對一個不存在的 `key` 進行 `BITCOUNT` 操作,結果為 `0` 。
**可用版本:**
>= 2.6.0
**時間復雜度:**
O(N)
**返回值:**
被設置為 `1` 的位的數量。
```
redis> BITCOUNT bits
(integer) 0
redis> SETBIT bits 0 1 # 0001
(integer) 0
redis> BITCOUNT bits
(integer) 1
redis> SETBIT bits 3 1 # 1001
(integer) 0
redis> BITCOUNT bits
(integer) 2
```
## 模式:使用 bitmap 實現用戶上線次數統計
Bitmap 對于一些特定類型的計算非常有效。
假設現在我們希望記錄自己網站上的用戶的上線頻率,比如說,計算用戶 A 上線了多少天,用戶 B 上線了多少天,諸如此類,以此作為數據,從而決定讓哪些用戶參加 beta 測試等活動 —— 這個模式可以使用 [_SETBIT_](setbit.html#setbit) 和 [_BITCOUNT_](#bitcount) 來實現。
比如說,每當用戶在某一天上線的時候,我們就使用 [_SETBIT_](setbit.html#setbit) ,以用戶名作為 `key` ,將那天所代表的網站的上線日作為 `offset` 參數,并將這個 `offset` 上的為設置為 `1` 。
舉個例子,如果今天是網站上線的第 100 天,而用戶 peter 在今天閱覽過網站,那么執行命令 `SETBIT peter 100 1` ;如果明天 peter 也繼續閱覽網站,那么執行命令 `SETBIT peter 101 1` ,以此類推。
當要計算 peter 總共以來的上線次數時,就使用 [_BITCOUNT_](#bitcount) 命令:執行 `BITCOUNT peter` ,得出的結果就是 peter 上線的總天數。
更詳細的實現可以參考博文(墻外) [Fast, easy, realtime metrics using Redis bitmaps](http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/) 。
## 性能
前面的上線次數統計例子,即使運行 10 年,占用的空間也只是每個用戶 10*365 比特位(bit),也即是每個用戶 456 字節。對于這種大小的數據來說, [_BITCOUNT_](#bitcount) 的處理速度就像 [_GET_](get.html#get) 和 [_INCR_](incr.html#incr) 這種 O(1) 復雜度的操作一樣快。
如果你的 bitmap 數據非常大,那么可以考慮使用以下兩種方法:
1. 將一個大的 bitmap 分散到不同的 key 中,作為小的 bitmap 來處理。使用 Lua 腳本可以很方便地完成這一工作。
2. 使用 [_BITCOUNT_](#bitcount) 的 `start` 和 `end` 參數,每次只對所需的部分位進行計算,將位的累積工作(accumulating)放到客戶端進行,并且對結果進行緩存 (caching)。
- Redis 文檔
- 鍵空間通知(keyspace notification)
- 事務(transaction)
- 發布與訂閱(pub/sub)
- 復制(Replication)
- 通信協議(protocol)
- 持久化(persistence)
- Sentinel
- 集群教程
- Redis 集群規范
- Redis 命令參考
- Key(鍵)
- DEL
- DUMP
- EXISTS
- EXPIRE
- EXPIREAT
- KEYS
- MIGRATE
- MOVE
- OBJECT
- PERSIST
- PEXPIRE
- PEXPIREAT
- PTTL
- RANDOMKEY
- RENAME
- RENAMENX
- RESTORE
- SORT
- TYPE
- SCAN
- String(字符串)
- APPEND
- BITCOUNT
- BITOP
- DECR
- DECRBY
- GET
- GETBIT
- GETRANGE
- GETSET
- INCR
- INCRBY
- INCRBYFLOAT
- MGET
- MSET
- MSETNX
- PSETEX
- SET
- SETBIT
- SETEX
- SETNX
- SETRANGE
- STRLEN
- Hash(哈希表)
- HDEL
- HEXISTS
- HGET
- HGETALL
- HINCRBY
- HINCRBYFLOAT
- HKEYS
- HLEN
- HMGET
- HMSET
- HSET
- HSETNX
- HVALS
- HSCAN
- List(列表)
- BLPOP
- BRPOP
- BRPOPLPUSH
- LINDEX
- LINSERT
- LLEN
- LPOP
- LPUSH
- LRANGE
- LREM
- LSET
- LTRIM
- RPOP
- RPOPLPUSH
- RPUSH
- RPUSHX
- Set(集合)
- SADD
- SCARD
- SDIFF
- SDIFFSTORE
- SINTER
- SINTER
- SINTERSTORE
- SISMEMBER
- SMEMBERS
- SMOVE
- SPOP
- SRANDMEMBER
- SREM
- SUNION
- SUNIONSTORE
- SSCAN
- SortedSet(有序集合)
- ZADD
- ZCARD
- ZCOUNT
- ZINCRBY
- ZRANGE
- ZRANGEBYSCORE
- ZRANK
- ZREM
- ZREMRANGEBYRANK
- ZREMRANGEBYSCORE
- ZREVRANGE
- ZREVRANGEBYSCORE
- ZREVRANK
- ZSCORE
- ZUNIONSTORE
- ZINTERSTORE
- ZSCAN
- Pub/Sub(發布/訂閱)
- PSUBSCRIBE
- PUBLISH
- PUBSUB
- PUNSUBSCRIBE
- SUBSCRIBE
- UNSUBSCRIBE
- Transaction(事務)
- DISCARD
- EXEC
- MULTI
- UNWATCH
- WATCH
- Script(腳本)
- EVAL
- EVALSHA
- SCRIPT EXISTS
- SCRIPT FLUSH
- SCRIPT KILL
- SCRIPT LOAD
- Connection(連接)
- AUTH
- ECHO
- PING
- QUIT
- SELECT
- Server(服務器)
- BGREWRITEAOF
- BGSAVE
- CLIENT GETNAME
- CLIENT KILL
- CLIENT LIST
- CLIENT SETNAME
- CONFIG GET
- CONFIG RESETSTAT
- CONFIG REWRITE
- CONFIG SET
- DBSIZE
- DEBUG OBJECT
- DEBUG SEGFAULT
- FLUSHALL
- FLUSHDB
- INFO
- LASTSAVE
- MONITOR
- PSYNC
- SAVE
- SHUTDOWN
- SLAVEOF
- SLOWLOG
- SYNC
- TIME
- 關于