Redis新API(Bitmap,GEO)
1.Bitmap 位图
1.1 Redis从2.2.0版本开始新增了setbit,getbit,bitcount等几个bitmap相关命令。虽然是新命令,但是并没有新增新的数据类型,因为setbit等命令只不过是在set上的扩展,因为redis存储String类型的数据是以二进制的形式存储,只不过bitmap是运用了二进制,不用String类型。
1.2 命令
命令 | 说明 |
---|---|
setbit key offset value | 设置指定键的二进制位图指定offset偏移量为value[0/1] |
getbit key offset | 获取指定键的二进制位图指定offset偏移量上的value |
bitcount key [start] [end] | 获取指定键的二进制位图所有的value为1有多少位 |
bitop [operation] destkey key [key …] | 对指定键做运算并把结果放入destkey目标键中,operation操作有 【AND 与运算 , OR 或运算 , XOR 异或运算 , NOT 非运算】 |
bitfield key [operation] [u/i]offset value | get是取出key对应的位图,指定value索引位开始,取offset位偏移量的二进制; |
1.3 命令demo演示
- setbit key offset value
设置指定key的offset位上的bit值为value,value只能是1或0,返回在offset处原来的bit值setbit lzj 0 1 #返回值 0
- getbit key offset
获取offset处的bit值getbit lzj 0 #返回值 1
- bitcount key [start] [end]
获取开始索引 到 结束索引 之间bit值为1 的数量bitcount lzj 0 -1 #返回值 1
- bitop [operation] destkey key [key …]
把指定的多个键的二进制进行计算操作,并把计算后的二进制放入指定键中,返回结果放入键中字符串长度,最多只能处理64个连续的位。setbit lzj1 0 1 bitop and result lzj lzj1 #返回值1
- bitfield key [operation] [u/i]offset value
get是取出key对应的位图,指定value索引位开始,取offset位偏移量的二进制;bitfield result get u8 0 #返回128 bitfield result get i8 0 #返回-128 #其他 还没有弄懂
1.4 下面可以用java代码通过redistemplate去获取一个字符串的二进制位图
@SpringBootTest(classes = RedissiondemoApplication.class)
class ShopServiceImplTest {@Autowiredprivate RedisTemplate<String,String> redisTemplate;@Testvoid consumer() {redisTemplate.opsForValue().set("lzj","jj");String res = redisTemplate.opsForValue().get("lzj");//输出一个String类型的bitmap位图System.out.println(toBinary(res.getBytes()));//输出十进制数组System.out.println(Arrays.toString(res.getBytes()));}public static String toBinary(byte[] bytes){//把字符串转成字符数组StringBuilder result= new StringBuilder();for(int i=0;i<bytes.length;i++){//byte是8位的,而int是32位,直接转换会在前面补24个1,所以 & 0xFF 消除掉StringBuilder binary= new StringBuilder(Integer.toBinaryString(bytes[i] & 0xFF));int len=8-binary.length();if(len>0){//不足8位补够for(int j=0;j<len;j++){binary.insert(0,"0");}}result.append(binary).append(" ");}return result.toString();}
}
可以看到从右到左是从低位到高位,二进制(8bit)转化为 十进制数组。
1.5 Bitmap怎么使用,根据二进制形式 是0 1 组成,所以我们可以用来做为一个用户的签到,用户签到就是1,没有签到就是 0(因为限制大小时512M就是2^32-1位),下面我将实现一个简单的demo。
1.6
@SpringBootTest(classes = RedissiondemoApplication.class)
public class Demo1 {@Autowiredprivate RedisTemplate<String,String> redisTemplate;/*** 用户签到** @param uid 用户ID* @param date 日期* @return 之前的签到状态*/public boolean doSign(int uid, LocalDate date) {int offset = date.getDayOfMonth() - 1;return redisTemplate.opsForValue().setBit(buildSignKey(uid, date), offset, true);}/*** 检查用户是否签到** @param uid 用户ID* @param date 日期* @return 当前的签到状态*/public boolean checkSign(int uid, LocalDate date) {int offset = date.getDayOfMonth() - 1;return redisTemplate.opsForValue().getBit(buildSignKey(uid, date), offset);}/*** 获取用户签到次数** @param uid 用户ID* @param date 日期* @return 当前的签到次数*/public long getSignCount(int uid, LocalDate date) {return redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(buildSignKey(uid, date).getBytes()));}public static String toBinary(byte[] bytes){//把字符串转成字符数组StringBuilder result= new StringBuilder();for(int i=0;i<bytes.length;i++){//byte是8位的,而int是32位,直接转换会在前面补24个1,所以 & 0xFF 消除掉StringBuilder binary= new StringBuilder(Integer.toBinaryString(bytes[i] & 0xFF));int len=8-binary.length();if(len>0){//不足8位补够for(int j=0;j<len;j++){binary.insert(0,"0");}}result.append(binary).append(" ");}return result.toString();}/*** 获取当月连续签到次数** @param uid 用户ID* @param date 日期* @return 当月连续签到次数*/public long getContinuousSignCount(int uid, LocalDate date) {int signCount = 0;System.out.println(date.getDayOfMonth());//命令: bitfield key get [u/i]offset value 此命令就是get取出key对应的位图,指定value索引位开始,取offset位偏移量的二进制BitFieldSubCommands bitFieldSubCommands = BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(date.getDayOfMonth())).valueAt(0);List<Long> list = redisTemplate.opsForValue().bitField(buildSignKey(uid, date),bitFieldSubCommands);if (list != null && list.size() > 0) {// 取低位连续不为0的个数即为连续签到次数,需考虑当天尚未签到的情况long v = list.get(0) == null ? 0 : list.get(0);for (int i = 0; i < date.getDayOfMonth(); i++) {//因为取的是无符号的二进制,所以右移一位,左移一位,依然相等只有是最右边是0[没签到]的时候,if (v >> 1 << 1 == v) {// 只有除了第一天以外没签到,才算断签。if (i > 0) break;} else {// 签到了 签到数加1signCount += 1;}//右移一位并赋值,相当于把最左边一位去除v >>= 1;}}return signCount;}/*** 获取当月首次签到日期** @param uid 用户ID* @param date 日期* @return 首次签到日期*/public LocalDate getFirstSignDate(int uid, LocalDate date) {Long pos = redisTemplate.execute((RedisCallback<Long>) con -> con.bitPos(buildSignKey(uid, date).getBytes(), true));return pos < 0 ? null : date.withDayOfMonth((int) (pos + 1));}/*** 获取当月连续签到次数** @param uid 用户ID* @param date 日期* @return 当月连续签到次数*/public long getContinuousSignCount(int uid, LocalDate date) {int signCount = 0;System.out.println(date.getDayOfMonth());//命令: bitfield key get [u/i]offset value BitFieldSubCommands bitFieldSubCommands = BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(date.getDayOfMonth())).valueAt(0);List<Long> list = redisTemplate.opsForValue().bitField(buildSignKey(uid, date),bitFieldSubCommands);if (list != null && list.size() > 0) {// 取低位连续不为0的个数即为连续签到次数,需考虑当天尚未签到的情况long v = list.get(0) == null ? 0 : list.get(0);for (int i = 0; i < date.getDayOfMonth(); i++) {//因为取的是无符号的二进制,所以右移一位,左移一位,依然相等只有是最右边是0[没签到]的时候,if (v >> 1 << 1 == v) {// 只有除了第一天以外没签到,才算断签。if (i > 0) break;} else {// 签到了 签到数加1signCount += 1;}//右移一位并赋值,相当于把最左边一位去除v >>= 1;}}return signCount;}private static String formatDate(LocalDate date) {return formatDate(date, "yyyyMM");}private static String formatDate(LocalDate date, String pattern) {return date.format(DateTimeFormatter.ofPattern(pattern));}private static String buildSignKey(int uid, LocalDate date) {return String.format("u:sign:%d:%s", uid, formatDate(date));}private Integer ID = 2017131132;/*** 当天签到*/@Testvoid sign() {LocalDate today = LocalDate.now().minusDays(1);String todayDate = formatDate(today,"yyyyMMdd");System.out.println(doSign(ID, today)==true?"已签到【" + todayDate + "】":"签到成功【" + todayDate + "】");}/*** 检查当天是否签到*/@Testvoid checkSign(){LocalDate today = LocalDate.now().minusDays(1);String todayDate = formatDate(today,"yyyyMMdd");System.out.println(checkSign(ID,today)==true?"【" + todayDate + "】已签到":"【" + todayDate + "】未签到");}/*** 获取今月 签到次数*/@Testvoid getSignCount(){LocalDate today = LocalDate.now();long signCount = getSignCount(ID, today);System.out.println(today.getMonth().getValue() + "月份签到了" + signCount + "次");}/*** 获取连续签到次数* 注意: 如果当天没有签到是不算做断签,因为当天可以签到,如果前天没有签到就是断签了,不属于连续签到计算范围*/@Testvoid getContinuousSignCount(){LocalDate today = LocalDate.now();long continuousSignCount = getContinuousSignCount(ID, today);System.out.println("连续签到" + continuousSignCount + "天");}/*** 获取第一天签到*/@Testvoid getFirstSignDate(){LocalDate today = LocalDate.now();LocalDate firstSignDate = getFirstSignDate(ID, today);System.out.println("首次签到日期是" + formatDate(firstSignDate,"yyyyMMdd"));}/*** 获取用户的签到信息*/@Testvoid getSignInfo(){LocalDate today = LocalDate.now();getSignInfo(ID, today).forEach((k,v) -> {System.out.println(k + " : " + (v ?"√":"×"));});}}
2.GEO
redis 3.2版本以上 才能使用的API
API | 作用 |
---|---|
GEOADD key longitude latitude member | 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中 |
GEOPOS key member [member …] | 用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。 |
GEODIST key member1 member2 [m/km/ft/mi] | 用于返回两个给定位置之间的距离。 |
GEORADIUS key longitude latitude radius [m/km/ft/mi] | 获取以指定坐标内半径为raduis的圆内的元素个数 |
GEORADIUSBYMEMBER key member radius [m/km/ft/mi] | 获取以指定键的成员的内半径为raduis的圆内的元素个数 |
GEOHASH key member [member …] | geohash 来保存地理位置的坐标。 |
- GEOADD key longitude latitude member
用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中geoadd lzj 113.762141 22.978418 "广东科技学院" geoadd lzj 113.769143 22.933629 "水濂山森林公园"
- GEOPOS key member [member …]
用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。geopos lzj "广东科技学院" geopos lzj "水濂山森林公园"
- GEODIST key member1 member2 [m/km/ft/mi]
用于返回两个给定位置之间的距离。
–geodist lzj "广东科技学院" "水濂山森林公园" km
- GEORADIUS key longitude latitude radius [m/km/ft/mi]
和GEODIST作用一样,但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点。
– WITHDIST : 返回距离
– WITHCOORD : 返回经纬度
– WITHHASH : 返回geohash值
– [ASC/DESC] : 规定距离排序顺序
– COUNT : 返回的指定记录数georadius lzj 113 22 5 km
- GEORADIUSBYMEMBER key member radius [m/km/ft/mi]
获取以指定键的成员的内半径为raduis的圆内的元素个数
– WITHDIST : 返回距离
– WITHCOORD : 返回经纬度
– WITHHASH : 返回geohash值
– [ASC/DESC] : 规定距离排序顺序
– COUNT : 返回的指定记录数georadiusbymember lzj "广东科技学院" 7 km
- GEOHASH key member [member …]
geohash 来保存地理位置的坐标geohash lzj "广东科技学院"
一键查询淘宝/拼多多内部优惠券,每日大额外卖红包,购物省钱的宝藏工具
Redis新API(Bitmap,GEO)相关推荐
- 03 redis新类型bitmap/hyperloglgo/GEO
亿级系统中常见的四种统计 聚合统计 统计多个集合元素的聚合结果,就是前面讲解过的交差并等集合统计 交并差集和聚合函数的应用 排序统计 抖音视频最新评论留言的场景,请你设计一个展现列表.考察你的数据结构 ...
- Redis数据实战之GEO在LBS中应用与自定义新数据类型
Redis数据实战之GEO在LBS中应用与自定义新数据类型 引言 面向 LBS 应用的 GEO 数据类型 GEO 的底层结构 GeoHash 的编码方法 如何操作 GEO 类型 如何自定义数据类型 R ...
- 六、Redis新类型bitmap-hyperloglgo-GEO
六.Redis新类型bitmap-hyperloglgo-GEO 1.统计 存的进+取得快+多统计 1.统计的类型有哪些? 1.聚合统计 统计多个集合元素的聚合结果,就是前面讲解过的交差并等集合统计 ...
- redis 用setbit(bitmap)统计活跃用户
getspool.com的重要统计数据是实时计算的.Redis的bitmap让我们可以实时的进行类似的统计,并且极其节省空间.在模拟1亿2千8百万用户的模拟环境下,在一台MacBookPro上,典型的 ...
- php版redis插件,SSDB数据库,增强型的Redis管理api实例
php版redis插件,SSDB数据库,增强型的Redis管理api实例 SSDB是一套基于LevelDB存储引擎的非关系型数据库(NOSQL),可用于取代Redis,更适合海量数据的存储. 另外,r ...
- redis 经纬度_【SpringBoot DB 系列】Redis 高级特性之 GEO
[SpringBoot DB 系列]Redis 高级特性之 GEO GEO 用于存储地理信息,最直观的就是我们日常使用的地图 app 中,如果我想查询我所在地的周边餐饮,就可以利用 geo 中的以(x ...
- Redis6发布订阅及Redis新数据类型
Redis6 Redis的发布和订阅 什么是发布和订阅 Redis的发布和订阅 发布订阅命令行实现 Redis新数据类型 Bitmaps 常用命令 1.setbit 2.实例 3. getbit 4. ...
- PyTorch 1.9发布,支持新API,可在边缘设备中执行
点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 来源丨机器之心 编辑丨极市平台 导读 PyTorch 团队发布了 P ...
- hbase建索引java api_hbase java api样例(版本1.3.1,新API)
hbase版本:1.3.1 目的:HBase新API的使用方法. 尝试并验证了如下几种java api的使用方法. 1.创建表 2.创建表(预分区) 3.单条插入 4.批量插入 5.批量插入(客户端缓 ...
最新文章
- 确认!语音识别大牛Daniel Povey将入职小米,曾遭霍普金斯大学解雇,怒拒Facebook
- 2009年8月26日,用于win2003上的MSN不能正常使用
- 解决Ubuntu与Windows之间无法复制粘贴问题
- 苹果决定不修复 Big Sur 和 Catalina 中的这两个0day
- Windows Mobile Sensors API库的设计
- Kubernetes 小白学习笔记(4)--kubernetes是什么
- 理解SNS系列之二:更进一步,近观SNS
- Gliffy Diagrams 好用的流程图工具
- 打蚊子表情包_打死蚊子表情包 - 打死蚊子微信表情包 - 打死蚊子QQ表情包 - 发表情 fabiaoqing.com...
- 与美不期而遇:Carry on Till Tomorrow
- 有道云笔记markdown字体增大、生成目录
- 国内可用的 ChatGPT
- mstsc连接传输大文件时突然中断
- 第一课 request传参
- IIS配置反向代理URL rewrite.dll加载失败
- 开发规范及具体开发任务分工
- 玻璃幕墙清洗机器人市场前景_玻璃幕墙越障清洁机器人
- gdb调试程序时跳进函数和跳出函数
- 用c语言实现cos x 函数
- CASIA-OLHWDB2.0-2.2数据集wptt文件解析
热门文章
- AEG-12A-02-D2-2-50,AEG-12A-02-D2-C-50比例阀控制器
- AMD负责YES,英特尔负责赚钱
- 大砍广告投放,还威胁要下架Twitter,马斯克怒向苹果开炮:宁可开战也不付30%“过路费”
- AIBlockChain:“知名博主独家讲授”人工智能创新应用竞赛【精选实战作品】之《基于计算机视觉、自然语言处理、区块链和爬虫技术的智能会议系统》软件系统案例的界面简介、功能介绍分享之总篇
- 怎么给电话手表安上Android,电话手表安卓版
- 在win10中开启64位ie浏览器的方法(IE11)
- 中职计算机vb听课记录,中职学校《VB语言程序设计》教学浅析
- 计算机专业的职业树,计算机专业职业生涯规划
- 淘宝,tmall,1688,抖音,拼多多等平台商品详情接口(网络爬虫数据接口调用示例)接口对接教程
- 手机android的文件怎么恢复,如何恢复安卓手机内置存储中已删除的文件