Skip to content

Commit

Permalink
增加 BITCOUNT 和 BITOP 命令
Browse files Browse the repository at this point in the history
  • Loading branch information
huangzworks committed Jul 12, 2012
1 parent dc5b3fb commit b7d8c26
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 24 deletions.
4 changes: 2 additions & 2 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ Redis 命令参考
| - :doc:`key/migrate` | - :doc:`string/incrbyfloat` | | |
| - :doc:`key/dump` | - :doc:`string/setbit` | | |
| - :doc:`key/restore` | - :doc:`string/getbit` | | |
| | | | |
| | | | |
| | - :doc:`string/bitop` | | |
| | - :doc:`string/bitcount` | | |
| | | | |
+-----------------------------------+-------------------------------------------+---------------------------------------+-----------------------------------+
| | | | | | | | |
Expand Down
68 changes: 68 additions & 0 deletions string/bitcount.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.. _bitcount:

BITCOUNT
===========

**BITCOUNT key [start] [end]**

计算给定字符串中,被设置为 ``1`` 的比特位的数量。

一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 ``start`` 或 ``end`` 参数,可以让计数只在特定的位上进行。

``start`` 和 ``end`` 参数的设置和 :ref:`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 测试等活动 —— 这个模式可以使用 :ref:`SETBIT` 和 `BITCOUNT` 来实现。

比如说,每当用户在某一天上线的时候,我们就使用 :ref:`SETBIT` ,以用户名作为 ``key`` ,将那天所代表的网站的上线日作为 ``offset`` 参数,并将这个 ``offset`` 上的为设置为 ``1`` 。

举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 ``SETBIT peter 100 1`` ;如果明天 peter 也继续阅览网站,那么执行命令 ``SETBIT peter 101 1`` ,以此类推。

当要计算 peter 总共以来的上线次数时,就使用 `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` 的处理速度就像 :ref:`GET` 和 :ref:`INCR` 这种 O(1) 复杂度的操作一样快。

如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法:

1. 将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。

2. 使用 `BITCOUNT` 的 ``start`` 和 ``end`` 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。
44 changes: 22 additions & 22 deletions string/bitop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ BITOP

当 `BITOP`_ 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 ``0`` 。

空的 ``key`` 也被看作包含 ``0`` 的字符串序列。
空的 ``key`` 也被看作是包含 ``0`` 的字符串序列。

**可用版本:**
>= 2.6.0
Expand All @@ -32,38 +32,38 @@ BITOP
O(N)

**返回值:**
保存到 ``destkey`` 的字符串的长度,和输入 ``key`` 中最长的字符串相等
保存到 ``destkey`` 的字符串的长度,和输入 ``key`` 中最长的字符串长度相等

.. note:: `BITOP`_ 的复杂度为 O(N) ,当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点。

::

redis> SET bits-1 1111
OK
redis 127.0.0.1:6379> SETBIT bits-1 0 1 # bits-1 = 1001
(integer) 0

redis> SET bits-2 1001
OK
redis 127.0.0.1:6379> SETBIT bits-1 3 1
(integer) 0

redis> BITOP AND and-bits bits-1 bits-2
(integer) 4
redis 127.0.0.1:6379> SETBIT bits-2 0 1 # bits-2 = 1011
(integer) 0

redis> GET and-bits
"1001"
redis 127.0.0.1:6379> SETBIT bits-2 1 1
(integer) 0

redis> BITOP XOR xor-bits bits-1 bits-2
(integer) 4
redis 127.0.0.1:6379> SETBIT bits-2 3 1
(integer) 0

redis> GET xor-bits # 0110
"\x00\x01\x01\x00"
redis 127.0.0.1:6379> BITOP AND and-result bits-1 bits-2
(integer) 1

redis> BITOP NOT negation-bits bits-2
(integer) 4
redis 127.0.0.1:6379> GETBIT and-result 0 # and-result = 1001
(integer) 1

redis> GET negation-bits # 0110
"\xce\xcf\xcf\xce"
redis 127.0.0.1:6379> GETBIT and-result 1
(integer) 0

redis 127.0.0.1:6379> GETBIT and-result 2
(integer) 0

模式:使用位图实现实时矩阵运算
----------------------------------

请参见 :doc:`bitcount` 命令。
redis 127.0.0.1:6379> GETBIT and-result 3
(integer) 1

0 comments on commit b7d8c26

Please sign in to comment.