这是Redis使用场景第二期,第一期见Redis五种常用基本类型
(一)Bitmaps
一、使用场景
【Bitmaps介绍】
- Redis提供的Bitmaps这个
数据结构
可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作。 - 可以把Bitmaps想象成一个以位为单位的数组,数组中的每个单元只能存0或1,数组的下标在bitmaps中叫做偏移量。
- 单个bitmaps的最大长度是512MB,即2^32个比特位
- bitmaps的最大优势是节省存储空间。例如在一个以自增id代表不同用户的系统中,我们只需要512MB空间就可以记录40亿用户的某个单一信息(比如用户是否希望接收新闻邮件)
- 有两种类型的位操作:一类是对特定bit位的操作,比如设置/获取某个特定比特位的值。另一类是批量bit位操作,例如在给定范围内统计为1的比特位个数
- Bitmap是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset),在bitmap上可执行AND,OR,XOR以及其他位操作。
【使用场景】
1)各种实时分析
2)存储与对象ID关联的布尔信息,要求高效且高性能
(1)以某电影网站为例
- 统计每天某一部电影是否被点播(一个bitmaps各个位代表的是不同的电影,获取某个特定比特位的值)
- 统计每天有多少部电影被点播(同上,批量bit位操作,在给定范围内统计为1的比特位个数)
- 统计每周/月/年有多少部电影被点播(在给定范围内统计为1的比特位个数)
- 统计年度哪部电影没有被点播(同上)
(2)以网站用户的最长连续访问天数为例(用户活跃数)
setbit user01 2 1 # 设置用户user01 第二天来访
setbit user01 3 1 # 设置用户user01 第三天来访
bitcount user01 # 查询user01来访天数
bitpos user01 2 # 返回1,查询用户user01第二天是否来访
-
例如你想知道自己网站用户的最长连续访问天数。从0开始计数,每当有用户访问时,使用setbit设置一个bit位,bit位的index可以这样生成:(当前unix时间戳-计数开始时的时间戳)/(3600*24)(每天的记录)
-
通过这种方法,你可以获取每个用户的每日来访记录。使用bitcount可以很容易的统计出某个特定用户的来访天数。使用几个bitpos命令,或者直接获取并分析对应的位图,就可以很容易的算出最长连续访问天数。
-
bitmaps通常被分割成多个key,以免单个key中存放的数据过大。有一个分割key的小技巧:每个key存放M个bit位,key以“比特数(bit-number)/M”命名。第N个bit位,对应key中的位置用“比特数(bit-number)模M”获得
-
假设我们每个key只存储100位,现在有一个id为8303的用户来访问。那么这个用户对应的key应该是83(8303/100),在key:83中,与之对应的位置应该是3(8303 mod 100)。使用如下命令记录该用户访问:
setbit 83 3 1
二、常用命令
-
获取指定key对应偏移量上的bit值
getbit key offset
返回特定bit位(offset)的值。如果试图获取的bit位在当前字串长度范围外,该命令返回0.
-
设置指定key对应偏移量上的bit值,value只能是1或是0(每个key的每一位都有一个含义)
setbit key offset value
offset:你要操作的是第几个bit位
value:这个位的值是多少
如果所操作的bit位超过了当前字串的长度,redis会自动增大字串长度。
-
对指定的key按位进行交,并,非,异或操作,并将结果保存到destKey中
bitop op destKey key1[key2...]
其中op 是 AND,OR,NOT,XOR这四种中的一种 -
统计指定key中1的数量
bitcount key [start end]
(二)HyperLogLog
HyperLogLog 是一种基数估算算法。所谓基数估算,就是估算在一批数据中,不重复元素的个数有多少。它不会存储元素本身,存储的是不同元素的个数;
一、使用场景
例如:对于 Google 主页面而言,同一个账户可能会访问 Google 主页面多次。于是,在诸多的访问流水中,如何计算出 Google 主页面每天被多少个不同的账户访问过就是一个重要的问题。那么对于 Google 这种访问量巨大的网页而言,其实统计出有十亿的访问量或者十亿零十万的访问量其实是没有太多的区别的。
因此,在这种业务场景下,为了节省成本,其实可以只计算出一个大概的值,而没有必要计算出精准的值。
对于上面的场景,可以使用HashMap
、BitMap
和HyperLogLog
来解决。对于这三种解决方案,这边做下对比:
HashMap
:使用hincrby key field num
自增;算法简单,统计精度高,对于少量数据建议使用,但是对于大量的数据会占用很大内存空间;BitMap
:位图算法,统计精度高,虽然内存占用要比HashMap
少,但是对于大量数据还是会占用较大内存;HyperLogLog
:存在一定误差,占用内存少,稳定占用 12k 左右内存,可以统计 2^64 个元素,对于上面举例的应用场景,建议使用。
二、基本用法
- 添加:
pfadd key value
- 获取元素个数:
pfcount key
- 合并两个元素并统计个数:
pfmerge all a1 a2
,其中all 为合并a1,a2后的元素名
(三)Geo
一、使用场景
RedisGEO
适合精度不是很高
的场景,微信附近的人用Redis GeoHash比较合适。但是滴滴打车精度高的场景一般用的是Google S2.
- 自如、蛋壳、链家、还有美团都有根据距离找房源或者商铺的功能,都是用的空间索引.
首先上传房源和店铺的时候,通过高德地图可以获取到目标物的经纬度,然后上传到Redis中。查询的时候根据自身所在位置的经纬度,然后加上范围,就能查询到附近的房源和店铺列表名称和经纬度,放到高德地图中,就能完美展现出列表来 - 美团外卖或者其他软件上都会有显示商家距离你有多少米
二、基本用法
- 添加地理位置的坐标:
geoadd key 经度 纬度 位置名称
- 获取地理位置的坐标:
geopos key 位置名称
- 计算两个位置之间的距离(默认单位是米):
geodist key 位置名称1 位置名称2
- 根据给定的
经纬度坐标
获取指定范围内的位置集合:georadius key 经度 维度 指定范围 单位
- 根据给定的
元素
获取指定范围内的位置集合:georadiusbymember key 元素名称 指定范围 单位
- 获取一个或多个位置对象的hash值(geohash):
geohash key 位置元素名称1 (位置元素名称2 ....)
- 删除某个位置元素:
zrem key 位置元素......
三、实战演练
这里的以重庆(chongqin)
(经维度:106.55 29.57)、上海(shanghai)
(120.55 30.55)为例,key为position1