一、BitMap是什么

通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身,value对应0或1,我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存空间。

二、Redis中的BitMap

Redis从2.2.0版本开始新增了setbit、getbit、bitcount等几个bitmap相关命令。虽然是新命令,但是并没有新增新的数据类型,因为setbit等命令只不过是在set上的扩展。

Redis的bitmap让我们可以实时的进行统计,并且极其节省空间。在模拟1亿2千8百万用户的模拟环境下,在一台MacBookPro上,典型的统计如“日用户数”(dailyunique users) 的时间消耗小于50ms, 占用16MB内存。

Bitmap是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset),在bitmap上可执行AND,OR,XOR以及其它位操作。

三、Redis中的命令

1、setbit

  语法:setbit key offset value

  描述:

    对key所储存的字符串值,设置或清除指定偏移量上的位(bit)。

    位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。

    当 key 不存在时,自动生成一个新的字符串值。

    字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。

  注意:

    offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。

    因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内, 所以用户能够使用的最大偏移量为 2^29-1(536870911) , 如果你需要使用比这更大的空间, 请使用多个 key。

    当生成一个很长的字符串时, Redis 需要分配内存空间, 该操作有时候可能会造成服务器阻塞(block)。 在2010年出产的Macbook Pro上, 设置偏移量为 536870911(512MB 内存分配)将耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配)将耗费约 80 毫秒, 设置偏移量 33554432(32MB 内存分配)将耗费约 30 毫秒, 设置偏移量为 8388608(8MB 内存分配)将耗费约 8 毫秒。

2、getbit

  语法:getbit key offset

  描述:

    对 key 所储存的字符串值,获取指定偏移量上的位(bit)。

    当 offset 比字符串值的长度大,或者 key 不存在时,返回 0

3、bitcount

  语法:bitcount key [start] [end]

  返回值:被设置为 1 的位的数量

  描述:

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

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

    start 和 end 参数的设置和 GETRANGE key start end 命令类似,都可以使用负数值: 比如 -1表示最后一个字节, -2 表示倒数第二个字节,以此类推。

    不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。

4、bitpos

5、bitop

  语法:bitop operation destkey key [key ...]

    operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:

    •   BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
    •   BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
    •   BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
    •   BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey 。

    除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。    

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

  描述:

    对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。

  注意:处理不同长度的字符串

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

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

  

6、bitfield

四、应用场景

1、位图计数统计

位图计数统计的是bitmap中值为1的位的个数。位图计数的效率很高,例如,一个bitmap包含10亿个位,90%的位都置为1,在一台MacBook Pro上对其做位图计数需要21.1ms。

例子:日活跃用户

为了统计今日登录的用户数,我们建立了一个bitmap,每一位标识一个用户ID。当某个用户访问我们的网页或执行了某个操作,就在bitmap中把标识此用户的位置为1。

每次用户登录时会执行一次redis.setbit(daily_active_users, user_id, 1)。将bitmap中对应位置的位置为1,时间复杂度是O(1)。统计bitmap结果显示有今天有9个用户登录。Bitmap的key是daily_active_users,它的值是1011110100100101。

因为日活跃用户每天都变化,所以需要每天创建一个新的bitmap。我们简单地把日期添加到key后面,实现了这个功能。例如要统计某一天有多少个用户访问,可以把这个bitmap的key设计为daily_active_users:2019-03-27。当用户访问进来,我们只是简单地在bitmap中把标识这个用户的位置为1,时间复杂度是O(1)。

备注:

Redis原生指令参考 http://redisdoc.com/index.html
Redis python客户端 方法参考 http://redis-py.readthedocs.io/en/latest/#indices-and-tables

Redis--位图BitMap的更多相关文章

  1. redis位图(bitmap)常用命令的解析

    描述   bitmap是redis封装的用于针对位(bit)的操作,其特点是计算效率高,占用空间少,常被用来统计用户签到.登录等场景 常用命令及解析 常用命令 setbit key offset va ...

  2. 基于Redis位图实现系统用户登录统计

    项目需求,试着写了一个简单登录统计,基本功能都实现了,日志数据量小.具体性能没有进行测试~ 记录下开发过程与代码,留着以后改进! 1. 需求 1. 实现记录用户哪天进行了登录,每天只记录是否登录过,重 ...

  3. Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  4. 基于Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  5. (算法)位图BitMap

    题目: 给定一数组,大小为M,数组中的数字范围为1-N,如果某带宽有限,无法传输该大小的数组,该怎么办? 思路: 通过位图BitMap来压缩数组,将数组中每个数字在bit位上标志,这样就可以将数组大小 ...

  6. Redis位图法记录在线用户的状态

    Redis位图法记录在线用户的状态 位图 Redis官方文档对于位图的介绍如下: 位图不是一个真实的数据类型,而是定义在字符串类型上的面向位的操作的集合.由于字符串类型是二进制安全的二进制大对象,并且 ...

  7. 巧用redis位图存储亿级数据与访问 - 简书

    原文:巧用redis位图存储亿级数据与访问 - 简书 业务背景 现有一个业务需求,需要从一批很大的用户活跃数据(2亿+)中判断用户是否是活跃用户.由于此数据是基于用户的各种行为日志清洗才能得到,数据部 ...

  8. EmguCV从位图(Bitmap)加载Image<Gray,byte>速度慢的问题

    先说背景.最近在用C#+EmguCV(其实就是用P/Invoke封闭了OpecCV,与OpenCVDotNet差不多) 做一个视频的东西.视频是由摄像头采集回来的1f/s,2048X1000大小,其实 ...

  9. 基于Redis分布式BitMap的应用

    一.序言 在实际开发中常常遇到如下需求:判断当前元素是否存在于已知的集合中,将已知集合中的元素维护一个HashSet,使用时只需耗时O(1)的时间复杂度便可判断出结果,Java内部或者Redis均提供 ...

  10. redis位图命令

    概述 redis 的位图就是01的数据格式,redis 主要做有写入,读取和统计.位图相关的命令 : 其中set和get就是 read 和writer , bitcount 统计相关,bitop 是对 ...

随机推荐

  1. Transformation functionality for the String class

    String类的转换功能: package com.itheima_05; /* * String类的转换功能: * char[] toCharArray():把字符串转换为字符数组 * String ...

  2. web.xml里welcome-file欢迎页面配置及web.xml简介

    web项目欢迎页面的配置 <welcome-file-list> <welcome-file>/WEB-INF/index.html</welcome-file> ...

  3. 解决MyEclipse不能导出war包

    原因:无法导出是由于软件破解不完成导致的: 解决办法: 找到MyEclipse安装目录下MyEclipse\Common\plugins文件夹中的com.genuitec.eclipse.export ...

  4. 【涨姿势】Prince2和PMP的区别,大多数人都没搞清楚!

    项目管理领域有2个流行的知识体系:      ☑ 一个是美国项目管理协会(PMI)开发的“项目管理知识体系(PMBOK,Project Management Body of Knowledge)”,目 ...

  5. ASP.NET中使用UpdatePanel时用Response输出出现错误的解决方法

    asp.net中执行到Response.write("xx");之类语句或Microsoft JScript 运行时错误: Sys.WebForms.PageRequestMana ...

  6. cef开启摄像头和录音

    参考资料:https://github.com/cztomczak/phpdesktop/wiki/Chrome-settings#command_line_switches CefSharp中文帮助 ...

  7. Gerrit安装配置

    环境: CentOS 1611 + gerrit-2.11.4 (review.openstack.org) 1. 安装java1.8 (>1.7) [root@review ~]# yum i ...

  8. 铁乐学python_Day41_线程01

    线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程. 程序和进程的区别就在于: 程序是 ...

  9. EF CodeFirst示例

    新建Web空项目,选择MVC相关基础组件 安装EntityFramework 添加模型和上下文对象 添加包含读写的控制器 点击添加报错 这时需要重新生成项目,然后再试尝试添加控制器,OK 为调试方便, ...

  10. c++中堆、栈内存分配

    转自:https://blog.csdn.net/qingtingchen1987/article/details/7698415 一个由C/C++编译程序占用内存分为以下几个部分1.栈区(stack ...