5.【Redis系列】Redis的高级应用-位图

原文:5.【Redis系列】Redis的高级应用-位图

假设一个应用场景:我们需要记录用户一年的签到记录,签到了是1,没签是0,记录365天,当用户上亿后,存储空间是惊人的。

为了解决这个问题,redis提供了位图的数据结构。这样每天的签到记录只占据一个位,365天就是365个位,46个字节完全可以容纳下。

位图不是特殊的数据结构,它的内容就是普通的字符串,也就是byte数组,我们可以用set/get方法来设置和获取位图的内容,也可以使用位图操作getbit和setbit将byte数组看成位数组来处理。

基本使用

Redis 的位数组是自动扩展,如果设置了某个偏移位置超出了现有的内容范围,就会自动将位数组进行零扩充。

接下来我们使用位操作将字符串设置为 hello (不是直接使用 set 指令),首先我们需要得到 hello 的 ASCII 码,用 Python 命令行可以很方便地得到每个字符的 ASCII 码的二进制值。

>>> bin(ord(‘h‘))
‘0b1101000‘   # 高位 -> 低位
>>> bin(ord(‘e‘))
‘0b1100101‘
>>> bin(ord(‘l‘))
‘0b1101100‘
>>> bin(ord(‘l‘))
‘0b1101100‘
>>> bin(ord(‘o‘))
‘0b1101111‘

image.png

接下来我们使用 redis-cli 设置第一个字符,也就是位数组的前 8 位,我们只需要设置值为 1 的位,如上图所示,h 字符只有 1/2/4 位需要设置,e 字符只有 9/10/13/15 位需要设置。值得注意的是位数组的顺序和字符的位顺序是相反的。

127.0.0.1:6379> setbit s 1 1
(integer) 0
127.0.0.1:6379> setbit s 2 1
(integer) 0
127.0.0.1:6379> setbit s 4 1
(integer) 0
127.0.0.1:6379> setbit s 9 1
(integer) 0
127.0.0.1:6379> setbit s 10 1
(integer) 0
127.0.0.1:6379> setbit s 13 1
(integer) 0
127.0.0.1:6379> setbit s 15 1
(integer) 0
127.0.0.1:6379> get s
"he"

上面这个例子可以理解为「零存整取」,同样我们还也可以「零存零取」,「整存零取」。「零存」就是使用 setbit 对位值进行逐个设置,「整存」就是使用字符串一次性填充所有位数组,覆盖掉旧值。

零存零取

127.0.0.1:6379> setbit w 1 1
(integer) 0
127.0.0.1:6379> setbit w 2 1
(integer) 0
127.0.0.1:6379> setbit w 4 1
(integer) 0
127.0.0.1:6379> getbit w 1  # 获取某个具体位置的值 0/1
(integer) 1
127.0.0.1:6379> getbit w 2
(integer) 1
127.0.0.1:6379> getbit w 4
(integer) 1
127.0.0.1:6379> getbit w 5
(integer) 0
零存零取

127.0.0.1:6379> set w h  # 整存
(integer) 0
127.0.0.1:6379> getbit w 1
(integer) 1
127.0.0.1:6379> getbit w 2
(integer) 1
127.0.0.1:6379> getbit w 4
(integer) 1
127.0.0.1:6379> getbit w 5
(integer) 0

如果对应位的字节是不可打印字符,redis-cli 会显示该字符的 16 进制形式。

127.0.0.1:6379> setbit x 0 1
(integer) 0
127.0.0.1:6379> setbit x 1 1
(integer) 0
127.0.0.1:6379> get x
"\xc0"

原文地址:https://www.cnblogs.com/lonelyxmas/p/12515047.html

时间: 2024-10-17 11:40:40

5.【Redis系列】Redis的高级应用-位图的相关文章

Nosql技术--redis系列--redis的数据类型 及相应的命令--String类型

1:redis的官方网站地址是:http://www.redis.com 在线redis命令运行测试地址:http://try.redis.io/ 2:redis的数据类型有5种:String .Hash .Set.List.SortedSet String 类型 1)String是二进制安全的 (1):set 表示设置key和value eg :> set name lusy ok >get name lusy 注意:redis中同一个name对应的value是一样的 (2)setnx:设置

Redis系列---redis简介01

一. 本章我们将用简短的几句话来帮助你快速的了解什么是redis,初学者不必深究 1 Redis简介 Remote Dictionary Server(Redis)是一个开源的使用ANSI C语言编写.支持网络.基于内存亦可持久化的日志型.key-value数据库,并提供多种语言的API 它通常被称为数据结构服务器,因为值value可以是字符串String,哈希Map,列表list,集合set和有序集合sorted set等类型 2 Redis特点 2.1优点: 1.支持多种数据结构,如 Str

10.【Redis系列】Redis的高级应用-GeoHash

原文:10.[Redis系列]Redis的高级应用-GeoHash Redis在3.2版本增加了GEO模板,意味着通过redis可以做附近的人,附近的门店,附近的商场这样的功能. 用数据库来算附近的人 地图元素的位置数据使用二维的经纬度表示,经度范围 (-180, 180],纬度范围 (-90, 90],纬度正负以赤道为界,北正南负,经度正负以本初子午线 (英国格林尼治天文台) 为界,东正西负.比如掘金办公室在望京 SOHO,它的经纬度坐标是 (116.48105,39.996794),都是正数

7.【Redis系列】Redis的高级应用-布隆过滤器

原文:7.[Redis系列]Redis的高级应用-布隆过滤器 拿今日头条来说,它会不停的给我们推荐新的新闻,每次推荐都要去重,过滤掉我们之前看过的内容,今日头条如何做到去重呢,我们上面的HyperLogLog虽然能去重,但是没有办法确认这个新闻有没有被浏览 过,没有pfcontains的方法.有没有更好的解决方案呢? Redis为我们准备了布隆过滤器,是专门用来解决这种去重问题的,它在起去重功能的同时,空间上还可以节约90%,只是稍微有一定的误判率. 什么是布隆过滤器 布隆过滤器可以理解为稍微不

9.【Redis系列】Redis的高级应用-漏斗限流

原文:9.[Redis系列]Redis的高级应用-漏斗限流 漏斗限流是最常用的限流方法之一,顾名思义,这个算法的灵感源于漏斗(funnel)的结构. image.png 漏斗的容量是有限的,如果将漏嘴堵住,然后一直往里面灌水,它就会变满,直至再也装不进去.如果将漏嘴放开,水就会往下流,流走一部分之后,就又可以继续往里面灌水.如果漏嘴流水的速率大于灌水的速率,那么漏斗永远都装不满.如果漏嘴流水速率小于灌水的速率,那么一旦漏斗满了,灌水就需要暂停并等待漏斗腾空. 所以,漏斗的剩余空间就代表着当前行为

8.【Redis系列】Redis的高级应用-简单限流

原文:8.[Redis系列]Redis的高级应用-简单限流 限流在分布式系统中是一个经常被提到的话题,如果当前系统的能力,不足以承受那么大的访问量的时候,那么我们就要阻止外来请求对系统继续施压 实现简单限流 首先我们来看一个常见的简单限流策略,系统要限制每个用户在一定时间内的某个行为只能操作N次,如何是用redis的数据结构来实现这个限流的功能呢. 解决方案 这个限流需求中存在一个滑动时间窗口,想想 zset 数据结构的 score 值,是不是可以通过 score 来圈出这个时间窗口来.而且我们

6.【Redis系列】Redis的高级应用-HyperLogLog

原文:6.[Redis系列]Redis的高级应用-HyperLogLog 老规矩还是先假设一个场景:比如京东的商品详情页,如果需要你来统计每天的UV数据,你会如何实现? 如果是PV就好办了,直接给每个网页增加一个计时器,每个网页增加一个日期,这样一进来incrby一次,最终可以计算出每天的统计所有的PV数据. 但是UV就不一样了,每一个用户进来多次每天也只能算一个UV.无论是登录用户还是未登录用户,都需要给一个唯一的ID来标识. 有可能你已经想到了通过set集合去重的功能,为每一个页面创建一个s

4.【Redis系列】Redis的高级应用-延时队列

原文:4.[Redis系列]Redis的高级应用-延时队列 我们习惯于用rabbitmq和kafka作为消息中间件,来给应用之间增加异步的能力.但是使用过的同学都知道,使用专业的消息中间件使用起来非常复杂,我们实现一个简单的功能都需要大量的操作.有了redis,可以让我解脱出来,使用redis可以非常轻松的搞定,Redis的消息队列不是专业的消息中间件,没有非常高级的特性,如果对消息的可靠性有极高的追求,那么redis的消息中间件可能不适合. 异步消息队列 Redis的列表可以用来处理消息队列,

Redis系列(2)之数据类型

Redis系列(2)之数据类型 <Redis系列(1)之安装>中介绍了Redis支持以下几种数据类型,那么本节主要介绍学习下这几种数据类型的基本操作 字符串类型,string 散列类型,hash 列表类型,list 集合类型,set 有序集合类型,zset 1. 字符串类型 赋值与取值 SET 与 GET. 当键不存在时候返回为空. 1 127.0.0.1:6379> set key hello 2 OK 3 127.0.0.1:6379> get key 4 "hell