• Bitmaps


    1. 简介

    现在计算机用二进制(位)作为信息的基础单位,1个字节等于8位,例如 "abc" 字符串是由3个字节组成,单实际在计算机存储时将其用二进制表示, "abc" 分别对应的 ASCII 码分别是97、98、99,对应的二进制分别是01100001、01100010和01100011,如下

    a >>>> 01100001

    b >>>> 01100010 >>>> abc >>>> 011000010110001001100011

    c >>>> 01100011

    合理地使用操作位能够有效的提高内存使用率和开发效率。

              Redis 提供了 Bitmaps 这个“数据类型”可以实现对位的操作:

            (1) Bitmaps 本身不是一种数据类型,实际上它就是字符串(key-value),但是它可以对字符串的位进行操作。

            (2) Bitmaps 单独提供了一套命令,所以在 Redis 中使用 Bitmaps 和使用字符串的方法不太相同。可以吧 Bitmaps 想象成一个以位为单位的数组,数组的每个单元智能存储0和1,数组的下标在 Bitmaps 中叫做偏移量。

    key >>>> value 011000010110001001100011

    2. 命令

     setbit

    (1)格式

     setbit 设置 Bitmaps 中某个偏移量的值(0或1)

    127.0.0.1:6379> setbit

    * offset :偏移量从0开始

    (2)实例

            每个独立用户是否访问过网站存放在 Bitmaps 中,将访问的用户记做1,没有访问的用户自作0,用偏移量记做用户的 id 。

            设置键的第 offset 个位的值(从0算起),假设现在有20个用户, userid =1,6,11,15,19的用户对网站进行了访问,那么当前 Bitmaps 初始化结果如图

    1234567891011121314151617181920
    012345678910111213141516171819
    01000010000100010001

     unique:users:20201106 代表2020-11-06这天的独立访问用户的 Bitmaps

    1. 127.0.0.1:6379> setbit unique:users:20201106 1 1
    2. (integer) 0
    3. 127.0.0.1:6379> setbit unique:users:20201106 6 1
    4. (integer) 0
    5. 127.0.0.1:6379> setbit unique:users:20201106 11 1
    6. (integer) 0
    7. 127.0.0.1:6379> setbit unique:users:20201106 15 1
    8. (integer) 0
    9. 127.0.0.1:6379> setbit unique:users:20201106 19 1
    10. (integer) 0

     注:

            很多应用的用户 id 以一个指定数字(例如10000)开头,直接将用户 id 和 Bitmaps 的偏移量对应势必会造成一定的浪费,通常的做法是每次做 setbit 操作时将用户 id 减去这个指定数字。

            在第一次初始化 Bitmaps 时,假如偏移量非常大,那么整个初始化过程执行会比较慢,可能会造成 Redis 的阻塞。

    getbit

    (1)格式

     getbit 获取 Bitmaps 中某个偏移量的值

    127.0.0.1:6379> getbit

    获取键的第 offset 位的值(从0开始算)

    (2)实例

    获取 id =8的用户是否在2020-11-06这天访问过,返回0说明没访问过:

    1. 127.0.0.1:6379> getbit unique:users:20201106 8
    2. (integer) 0
    3. 127.0.0.1:6379> getbit unique:users:20201106 1
    4. (integer) 1
    5. 127.0.0.1:6379> getbit unique:users:20201106 100
    6. (integer) 0

    注:因为100根本不存在,所以也是返回0

     bitcount

    统计字符串被设置为1的 bit 数。一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。 start 和 end 参数的设置,都可以使用负数值:比如-1表示最后一个位,而-2表示倒数第二个位, start 、 end 是指 bit 组的字节的下标数,二者皆包含。

    (1)格式

     bitcount [start end] 统计字符串从 start 字节到 end 字节比特值为1的数量

    127.0.0.1:6379> bitcount

     (2)实例

    计算2020-11-06这天的独立访问用户数量

    1. 127.0.0.1:6379> bitcount unique:users:20201106
    2. (integer) 5

     start 和 end 代表起始和结束字节数,下面操作计算用户 id 在第1个字节到第3个字节之间的独立访问用户数量,对应的用户 id 是11,15,19。

    1. 127.0.0.1:6379> bitcount unique:users:20201106 1 3
    2. (integer) 3

    举例:K1【01000001 01000000 00000000 00100001】,对应【0,1,2,3】

     bitcount K1 1 2  :统计下标1、2字节组中 bit =1的个数,即01000000 00000000 >>>> 1

     bitcount K1 1 3  :统计下标1、3字节组中 bit =1的个数,即01000000 00100001 >>>> 3

     bitcount K1 1 -2  :统计下标1、3字节组中 bit =1的个数,即01000000 00000000 >>>> 3

    注意: redis 的 setbit 设置或清除的是 bit 位置,而 bitcount 计算的是 byte 位置。

     

     bitop

    (1)格式

     bitop and (or/not/xor) [key...]

    127.0.0.1:6379> bittop

     bitop 是一个复合操作,他可以做多个 Bitmaps 的 and (交集)、 or (并集)、 not (非)、xor (异或)操作并将结果保存在 destkey中。

    (2)实例

    2020-11-04日访问网站的 userid =1,2,5,9

     setbit unique:users:20201104 1 1

     setbit unique:users:20201104 2 1

     setbit unique:users:20201104 5 1

     setbit unique:users:20201104 9 1

    2020-11-03日访问网站的 userid = 0,1,4,9

     setbit unique:users:20201103 0 1

     setbit unique:users:20201103 1 1

     setbit unique:users:20201103 4 1

     setbit unique:users:20201103 9 1

    计算出两天都访问过网站的用户数量

     bitop and unique:users:and:20201104_03

     unique:users:20201103 unique:users:20201104

    1. 127.0.0.1:6379> bitop and unique:users:and:20201104_03 unique:users:20201103 unique:users:20201104
    2. (integer) 2
    3. 127.0.0.1:6379> bitcount unique:users:and:20201104_03

    unique:users:202011040110010001
    0123456789

                                            ↓

    unique:users:202011031100100001
    0123456789

                                            ↓

    unique:users:20201104_030100000001
    0123456789

    计算出任意一天都访问过网站的用户数量(例如月活跃就是类似这种),可以使用 or 求并集

    1. 127.0.0.1:6379> bitop or unique:users:or:20201104_03 unique:users:20201103 unique:users:20201104
    2. (integer) 2
    3. 127.0.0.1:6379> bitcount unique:users:or:20201104_03
    4. (integer) 6

    3. Bitmaps 与 set 对比

            假设网站有1亿用户,每天独立访问的用户有5千万,如果每天用集合类型和 Bitmaps 分别存储活跃用户可以得到表

    set 和 Bitmaps 存储一天活跃用户对比
    数据类型每个用户 id 占用空间需要存储的用户量全部内存量
    集合类型64位5000000064位*50000000=400MB
     Bitmaps1位1000000001位*100000000=12.5MB

            很明显,这种情况下使用 Bitmaps 能节省很多的内存空间,尤其是随着时间推移节省的内存还是非常可观的

    set 和 Bitmaps 存储一天活跃用户对比
    数据类型一天一个月一年
    集合类型400MB12GB144GB
    Bitmaps12.5MB375MB4.5GB

            但 Bitmaps 并不是万金油,假如该网站每天的嘟噜访问用户很少,例如只有10万(大量的僵尸用户),那么两者的对比如下表所示,很显然,这时候使用 Bitmaps 就不太合适了,因为基本上大部分位都是0

    set 和 Bitmaps 存储一天活跃用户对比(独立用户比较少)
    数据类型每个用户 id 占用空间需要存储的用户量全部内存量
    集合类型64位10000064位*100000=800KB
     Bitmaps1位1000000001位*100000000=12.5MB

  • 相关阅读:
    uniapp 手机 真机测试 ​ 云打包 要是没申请 可以使用云打包 然后采用 测试权限即可​
    C#,数值计算——插值和外推,双线性插值(Bilin_interp)的计算方法与源程序
    clickhouse--join操作汇总【semi、anti、any、asof、global、colocate、cross】
    .NET WebAPI 自定义 NullableConverter 解决可为空类型字段入参“”空字符触发转换异常问题
    云轴科技ZStack信创云平台支撑长江航务管理局35套航运管理系统
    九、多项式朴素贝叶斯算法(Multinomial NB,Multinomial Naive Bayes)(有监督学习)
    花好月圆时,邀你一起来读诗!
    【Retinex theory】【图像增强】-笔记
    go 中如何实现定时任务
    volatile关键字 和 i = i + 1过程
  • 原文地址:https://blog.csdn.net/FairyKunKun/article/details/128128257