Redis点赞新思路 bitmap
1.使用场景
用户上线次数统计、统计活跃用户,签到,点赞等具有标识性功能
2.原理
就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身,是bit不是byte,1byte=8bit,优点凸显,就是贼鸡儿省空间
空间占用、以及第一次分配空间需要的时间
在一台2010MacBook Pro上,offset为2^32-1(分配512MB)需要~300ms,offset为2^30-1(分配128MB)需要~80ms,offset为2^28-1(分配32MB)需要~30ms,offset为2^26-1(分配8MB)需要8ms。<来自官方文档>
大概的空间占用计算公式是:($offset/8/1024/1024)MB)
说起来bitmap不能算为一种新数据类型,只是set的扩展
3.命令
命令 |
作用 |
---|---|
setbit |
设置Bitmap的值 |
getbit |
获取Bitmap的值 |
bitcount |
获取指定范围内值为1的个数 |
destkey |
对Bitmap做操作,可以是and(交集),or(并集),not(非集)或者xor(异或) |
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 作为输入 |
BITPOS |
BITPOS key bit [start][end]返回字符串里面第一个被设置为 1 或者 0 的bit位。 |
BITFIELD |
BITFIELD key [GET type offset][SET type offset value][INCRBY type offset increment][OVERFLOW WRAP|SAT|FAIL] |
溢出控制
用户可以通过 OVERFLOW 命令以及以下展示的三个参数, 指定 BITFIELD 命令在执行自增或者自减操作时, 碰上向上溢出(overflow)或者向下溢出(underflow)情况时的行为:
- WRAP :使用回绕(wrap around)方法处理有符号整数和无符号整数的溢出情况。对于无符号整数来说, 回绕就像使用数值本身与能够被储存的最大无符号整数执行取模计算, 这也是 C 语言的标准行为。对于有符号整数来说, 上溢将导致数字重新从最小的负数开始计算, 而下溢将导致数字重新从最大的正数开始计算。比如说, 如果我们对一个值为 127 的 i8 整数执行加一操作, 那么将得到结果 -128 。
- SAT :使用饱和计算(saturation arithmetic)方法处理溢出, 也即是说, 下溢计算的结果为最小的整数值, 而上溢计算的结果为最大的整数值。举个例子, 如果我们对一个值为 120 的 i8 整数执行加 10 计算, 那么命令的结果将为 i8 类型所能储存的最大整数值 127 。与此相反, 如果一个针对 i8 值的计算造成了下溢, 那么这个 i8 值将被设置为 -127 。
- FAIL :在这一模式下, 命令将拒绝执行那些会导致上溢或者下溢情况出现的计算, 并向用户返回空值表示计算未被执行。
需要注意的是, OVERFLOW 子命令只会对紧随着它之后被执行的 INCRBY 命令产生效果, 这一效果将一直持续到与它一同被执行的下一个 OVERFLOW 命令为止。在默认情况下, INCRBY 命令使用 WRAP 方式来处理溢出计算。
4.优点
省空间
5.缺点
暂无,虽然一个标识位只能记录一个用户,那也够用了毕竟你没有2^32-1的数据量
6.实现场景点赞
新增redis方法setbit
//bitmap
/**
* Sets the bit at {@code offset} in value stored at {@code key}.
*
* @param key must not be {@literal null}.
* @param offset
* @param value
* @since 1.5
* @see <a href="http://redis.io/commands/setbit">Redis Documentation: SETBIT</a>
*/
Boolean setBit(K key, long offset, boolean value);
/*
* setbit
* */
public Boolean setBitMap(String key,long commentDatailId,boolean value){
return redisTemplate.opsForValue().setBit(key,commentDatailId,value);
}
在命令中value是标识1或0的,也就是true/false对应值
key:设置的key,比如日活,签到,就用时间+id,那标识点赞未点赞就用信息id即可
offset:即所占标识位,一看就想起来偏移量
value:设置0/1
Boolean :返回0或1来标识是否
boolean flag = redisService.setBitMap(userIdStr,commentDetailId,true);
以前的逻辑不变set之前判断是否存在
if(redisService.getBitMap(userIdStr,commentDetailId)){
redisService.setBitMap(userIdStr,commentDetailId,true);
}else{
redisService.setBitMap(userIdStr,commentDetailId,false);
}
问题:如果我的id很大或者是uuid开始呢?
正常的id是不会的,但uuid有可能,如果是uuid可以使用uuid减去初始位来进行放置
实现场景大数据量黑名单
此业务适合大数据量业务存储的占用空间问题,而且基于redis速度不用担心
日活统计
bitop and time moday thurday
1.节约空间,统计一亿人每天的登录情况,用一亿bit,约1200WByte,约10M的字符就能表示(因为bitop命令的返回值是保存到 time中的字符串的长度(以字节byte为单位),和输入 key 中最长的字符串长度相等。即1亿除以8bit=1250万Byte);
2.计算方便
性能:
如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法:
● 将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。
● 使用 BITCOUNT 的 start 和 end 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。
何时使用:
如果活跃用户在百万级别,使用Redis BitMap很划算。
如果活跃用户很少,而用户id都是10位以上的int。那就很浪费内存了,还不如使用set集合,然后求交集就可以了。
- 简单易学的机器学习算法——Rosenblatt感知机
- 多级复制的数据不同步问题(r7笔记第11天)
- 简单易学的机器学习算法——Logistic回归
- Python 用OPEN读文件报错 ,路径以及r
- Oracle 12c PDB浅析(r9笔记第10天)
- merge语句导致的CPU使用率过高的优化(二) (r7笔记第9天)
- 网页爬虫-R语言实现基本函数
- Python中的random模块用于生成随机数
- 简单易学的机器学习算法——极限学习机(ELM)
- 图片数据集太少?Keras Image Data Augmentation 各参数详解
- 备库归档删除策略失效的问题分析 (r7笔记第6天)
- 优化算法——梯度下降法
- Java基础-26(02)总结网络编程
- 记一次数据同步需求的改进(二) (r7笔记第5天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【猫狗数据集】读取数据集的第二种方式
- django-模板之comment标签(六)
- 【猫狗数据集】对一张张图像进行预测(而不是测试集)
- 【猫狗数据集】pytorch训练猫狗数据集之创建数据集
- 【猫狗数据集】可视化resnet18的输出
- springmvc实例之修改雇员相关信息(四)
- 基于TypeScript封装Axios笔记(六)
- 蓝桥杯 k好数 java版
- 强烈推介的几个微信小程序开发小技巧,简单又实用
- 【pytorch-ssd目标检测】验证自己创建的数据集
- django-模板之自动转义autoescape(八)
- 【pytorch-ssd目标检测】测试自己创建的数据集
- 【pytorch-ssd目标检测】训练自己创建的数据集
- SwiftUI:更高级的 MKMapView
- spring AOP之重用切点表达式