目录
[1. 介绍](#1. 介绍)
[2. Bitmaps(可以称为字符串,专门进行位操作的字符串)](#2. Bitmaps(可以称为字符串,专门进行位操作的字符串))
[2.1 概念](#2.1 概念)
[2.2 setbit(设置Bitmaps中某个偏移量的值)](#2.2 setbit(设置Bitmaps中某个偏移量的值))
[2.3 getbit(获取Bitmaps中某个偏移量的值)](#2.3 getbit(获取Bitmaps中某个偏移量的值))
[2.4 bitcount(统计字符串被设置为1的bit数,访问过的用户为1,没有访问过的为0)](#2.4 bitcount(统计字符串被设置为1的bit数,访问过的用户为1,没有访问过的为0))
[2.5 bitop(复合操作,将多种情况的操作结果保存在destkey中)](#2.5 bitop(复合操作,将多种情况的操作结果保存在destkey中))
[3. HyperLogLog(做基数处理,去重等..)](#3. HyperLogLog(做基数处理,去重等..))
[3.1 概念](#3.1 概念)
[3.2 pfadd(添加指定元素到HyperLogLog中)](#3.2 pfadd(添加指定元素到HyperLogLog中))
[3.3 pfcount(计算HLL的近似基数)](#3.3 pfcount(计算HLL的近似基数))
[3.4 pfmerge(合并其它的key,进行计算等)](#3.4 pfmerge(合并其它的key,进行计算等))
[4. Geospatial(对经纬度,地理信息等操作)](#4. Geospatial(对经纬度,地理信息等操作))
[4.1 概念](#4.1 概念)
[4.2 geadd(添加地理位置)](#4.2 geadd(添加地理位置))
[4.3 geopos(获取指定地区的坐标值)](#4.3 geopos(获取指定地区的坐标值))
[4.4 geodist(获取两个位置之间的直线距离)](#4.4 geodist(获取两个位置之间的直线距离))
[4.5 georadius(以给定的经纬度为中心,找出某一半径内的元素)](#4.5 georadius(以给定的经纬度为中心,找出某一半径内的元素))
1. 介绍
在Redis 6中,有几种比较特殊且功能强大的数据结构:Bitmaps(位图)、HyperLogLog(超级对数日志)、Geospatial(地理空间)
- Bitmaps(位图):
- 作用:Bitmaps 是 Redis 中的一种非常紧凑和高效的数据结构,用来处理位操作相关的需求。
- 用途:主要用于记录某些状态或者事件是否发生过,例如用户是否点击过某个按钮、某天是否有用户访问网站等。因为它可以节省大量内存,特别适合于需要高效率地记录大量布尔型状态的场景。
- HyperLogLog(超级对数日志):
- 作用:HyperLogLog 是一种概率性数据结构,用于统计元素的基数(唯一元素的数量),占用固定大小的内存空间。
- 用途:适合于需要快速估计大数据集合中的唯一元素数量,例如统计网站的独立访客数、统计一周内不同IP地址访问网站的数量等。
- Geospatial(地理空间):
- 作用:Geospatial 是 Redis 提供的一种处理地理位置和坐标的数据结构,可以存储地理位置的经度和纬度,并支持相关的地理位置查询操作。
- 用途:适合于需要存储和查询地理位置信息的应用场景,如附近的商家搜索、地点推荐等。
2. Bitmaps(可以称为字符串,专门进行位操作的字符串)
2.1 概念
- Bitmaps本身不是数据类型,他只是字符串,专门进行位操作的字符串;
Bitmaps与set的区别:
提高了空间利用率,提高了cpu内存的利用率;
对比 set
和 Bitmaps
在存储独立用户空间方面的差异:
set
和Bitmaps
存储独立用户空间对比
数据类型 | 一天 | 一个月 | 一年 |
---|---|---|---|
set |
400MB | 12GB | 144GB |
Bitmaps |
12.5MB | 375MB | 4.5GB |
- 备注
Bitmaps
并不是万能的。如果网站每天的独立访问用户很少(例如只有 10 万,大量的僵尸用户),则对比情况如下。Bitmaps
在用户数量少的情况下不太适合,因为这时候大部分位都是0
,使其不太高效。
2.2 setbit(设置Bitmaps中某个偏移量的值)
SETBIT
命令用于设置 Bitmaps 中某个偏移量的值,可以将指定位置的位设置为 0 或 1;<key>
: Bitmaps 的键<offset>
: 偏移量,从 0 开始<value>
: 设置的值,只能是 0 或 1
ruby
SETBIT <key> <offset> <value>
ruby
# 设置键 `userbitmap` 在偏移量 5 处的位值为 1
127.0.0.1:6379> SETBIT userbitmap 5 1
(integer) 0
# 设置键 `userbitmap` 在偏移量 10 处的位值为 1
127.0.0.1:6379> SETBIT userbitmap 10 1
(integer) 0
# 设置键 `userbitmap` 在偏移量 5 处的位值为 0
127.0.0.1:6379> SETBIT userbitmap 5 0
(integer) 1
2.3 getbit(获取Bitmaps中某个偏移量的值)
GETBIT
命令用于获取 Bitmaps 中某个偏移量的值,返回该位的值(0 或 1);<key>
: Bitmaps 的键<offset>
: 偏移量,从 0 开始
ruby
GETBIT <key> <offset>
ruby
# 获取键 `userbitmap` 在偏移量 5 处的位值
127.0.0.1:6379> GETBIT userbitmap 5
(integer) 0
# 获取键 `userbitmap` 在偏移量 10 处的位值
127.0.0.1:6379> GETBIT userbitmap 10
(integer) 1
# 获取键 `userbitmap` 在偏移量 15 处的位值
127.0.0.1:6379> GETBIT userbitmap 15
(integer) 0
2.4 bitcount(统计字符串被设置为1的bit数,访问过的用户为1,没有访问过的为0)
BITCOUNT
命令用于统计 Bitmaps 中被设置为 1 的位的数量。该命令可以统计整个 Bitmaps 的 1 位数,也可以通过指定start
和end
参数来统计特定范围内的 1 位数;<key>
: Bitmaps 的键[start]
(可选): 开始的字节下标,负数表示从末尾开始计算[end]
(可选): 结束的字节下标,负数表示从末尾开始计算
ruby
BITCOUNT <key> [start end]
ruby
# 统计键 `userbitmap` 中所有被设置为 1 的位的数量
127.0.0.1:6379> BITCOUNT userbitmap
(integer) 2
ruby
# 统计键 `userbitmap` 在字节 0 到字节 1 范围内被设置为 1 的位的数量
127.0.0.1:6379> BITCOUNT userbitmap 0 1
(integer) 1
# 统计键 `userbitmap` 在最后 2 个字节范围内被设置为 1 的位的数量
127.0.0.1:6379> BITCOUNT userbitmap -2 -1
(integer) 1
2.5 bitop(复合操作,将多种情况的操作结果保存在destkey中)
BITOP
命令用于对多个 Bitmaps 进行位运算,包括 AND (交集)、OR (并集)、NOT (非)、XOR (异或)操作,并将结果存储在destkey
中;<operation>
: 运算类型,可以是AND
、OR
、NOT
、XOR
<destkey>
: 结果存储的目标键<key>
: 输入的源键,可以有一个或多个
ruby
BITOP <operation> <destkey> <key> [key...]
- 操作类型:
AND
: 交集(所有键中对应位都为 1,则结果位为 1)OR
: 并集(至少一个键中对应位为 1,则结果位为 1)NOT
: 非(键中对应位取反,NOT
只能有一个源键)XOR
: 异或(键中对应位不同则结果位为 1)
ruby
# 计算键 `bitmap1` 和 `bitmap2` 的位交集,结果存储在 `result`
127.0.0.1:6379> BITOP AND result bitmap1 bitmap2
(integer) <result-length>
ruby
# 计算键 `bitmap1` 和 `bitmap2` 的位并集,结果存储在 `result`
127.0.0.1:6379> BITOP OR result bitmap1 bitmap2
(integer) <result-length>
ruby
# 计算键 `bitmap1` 的位取反,结果存储在 `result`
127.0.0.1:6379> BITOP NOT result bitmap1
(integer) <result-length>
ruby
# 计算键 `bitmap1` 和 `bitmap2` 的位异或,结果存储在 `result`
127.0.0.1:6379> BITOP XOR result bitmap1 bitmap2
(integer) <result-length>
3. HyperLogLog(做基数处理,去重等..)
- Redis 提供了三种主要的 HyperLogLog 操作命令:
PFADD
、PFCOUNT
和PFMERGE
。这些命令允许我们高效地执行基数估计、添加元素、统计唯一元素数量、以及合并多个 HyperLogLog;
3.1 概念
- 在现代应用中,统计数据的基数(Unique Visitors,独立 IP 数,等)是常见需求。传统方法精确但耗费内存大,而 Redis 提供的 HyperLogLog 可以在较低的空间占用下高效估计集合的基数;
- 基数是集合中不重复元素的个数:数据集 {1, 3, 5, 7, 5, 7, 8},其基数集为 {1, 3, 5, 7, 8},基数为 5;
- 空间效率: 固定使用约 12 KB 内存;
- 适用场景: 处理大规模数据集,允许少量误差;
- 特点 :
- 不存储实际元素,仅用于基数估计;
- 可处理多达 2642^{64}264 个不同元素;
3.2 pfadd(添加指定元素到HyperLogLog中)
PFADD
命令用于向 HyperLogLog 中添加元素。如果这些元素是新出现的(即之前没有添加过),HyperLogLog 的估计基数将增加;<key>
: HyperLogLog 的键<element>
: 要添加的元素,可以是一个或多个
ruby
PFADD <key> <element> [element ...]
- 如果 HyperLogLog visitors 中没有这些元素,它会更新并增加基数估计:
ruby
# 添加用户 user1, user2, user3 到 HyperLogLog `visitors`
127.0.0.1:6379> PFADD visitors user1 user2 user3
(integer) 1 # 1 表示基数发生了变化
3.3 pfcount(计算HLL的近似基数)
PFCOUNT
命令返回 HyperLogLog 中估计的唯一元素数量。可以对单个或多个 HyperLogLog 进行基数估计;<key>
: HyperLogLog 的键,可以是一个或多个;
ruby
PFCOUNT <key> [key ...]
(integer)
表示估计的唯一元素数量:
ruby
# 统计 HyperLogLog `visitors` 中的唯一元素数量
127.0.0.1:6379> PFCOUNT visitors
(integer) 3 # 估计的唯一元素数
# 统计多个 HyperLogLog `visitors1`, `visitors2` 的合并基数
127.0.0.1:6379> PFCOUNT visitors1 visitors2
(integer) 5 # 合并估计的唯一元素数
3.4 pfmerge(合并其它的key,进行计算等)
PFMERGE
命令将多个 HyperLogLog 合并为一个目标 HyperLogLog。合并后的结果保存在指定的目标键中;<destkey>
: 目标 HyperLogLog 的键<sourcekey>
: 源 HyperLogLog 的键,可以是一个或多个
ruby
PFMERGE <destkey> <sourcekey> [sourcekey ...]
- 合并后的
total_visitors
将包含visitors1
和visitors2
的所有元素,并估计其总的唯一元素数量;- 返回值:
OK
表示操作成功
- 返回值:
ruby
# 合并 HyperLogLog `visitors1`, `visitors2` 到 `total_visitors`
127.0.0.1:6379> PFMERGE total_visitors visitors1 visitors2
OK
4. Geospatial(对经纬度,地理信息等操作)
4.1 概念
- Redis 3.2 中增加了对 GE0 类型的支持。GE0,Geographic,地理信息的缩写。该类型,就是元素的 2维坐标,在地图上就是经纬度。redis 基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度 Hash 等常见操作;
- 地理空间数据存储方式 :
- Redis 使用有序集合(Sorted Set)来存储地理空间数据。
- 每个成员(member)都有一个关联的分数(score),这个分数用来排序,通常用来表示成员的位置。
- 地理位置表示 :
- 每个地理位置通过经度(longitude)和纬度(latitude)来表示。
- Redis 使用二维平面坐标系来存储这些位置信息。
- 地理位置的索引 :
- 有序集合中的每个成员是一个地理位置的标识符,可以是任意字符串。
- 每个成员都有一个对应的地理坐标(经纬度),以及用来排序的分数。
4.2 geadd(添加地理位置)
GEADD
是一个用于向地理空间索引(Geo Index)添加成员的命令,它可以将带有经度和纬度信息的成员添加到指定的地理位置集合(GeoSet)中;<key>
: 地理位置集合(GeoSet)的键名。<longitude>
: 成员的经度。<latitude>
: 成员的纬度。<member>
: 要添加的成员名称。
ruby
GEADD <key> <longitude> <latitude> <member> [longitude latitude member...]
- 添加单个成员:
ruby
GEADD cities 13.361389 38.115556 "Palermo"
- 添加多个成员:
ruby
GEADD cities 15.087269 37.502669 "Catania" 13.361389 38.115556 "Palermo"
- 注意事项:
GEADD
命令会创建地理位置集合(如果它不存在),并将指定的成员添加到集合中。- 成员的经度和纬度需要是有效的浮点数值。
- 成员名称可以是任何字符串,但必须唯一标识该成员。
4.3 geopos(获取指定地区的坐标值)
GEOPOS
是用于获取地理位置集合(GeoSet)中成员的经度和纬度信息的命令。它可以用来查询指定成员在地理位置集合中的坐标信息;<key>
: 地理位置集合(GeoSet)的键名。<member>
: 要查询坐标信息的成员名称。
ruby
GEOPOS <key> <member> [member...]
-
返回值:
如果指定的成员存在于地理位置集合中,
GEOPOS
返回一个数组,每个成员的坐标用一个两元素的数组表示[longitude, latitude]
。如果成员不存在于集合中,返回nil
。 -
查询单个成员的坐标:
ruby
GEOPOS cities "Palermo"
ruby
假设 "Palermo" 的坐标是 `[13.361389, 38.115556]`,则命令返回:
ruby
1) 1) "13.361389"
2) "38.115556"
- 查询多个成员的坐标:
ruby
GEOPOS cities "Palermo" "Catania"
ruby
假设 "Palermo" 的坐标是 `[13.361389, 38.115556]`,"Catania" 的坐标是 `[15.087269, 37.502669]`,则命令返回:
ruby
1) 1) "13.361389"
2) "38.115556"
2) 1) "15.087269"
2) "37.502669"
- 注意事项:
GEOPOS
返回的坐标是以字符串形式表示的浮点数,分别代表经度和纬度。- 如果查询的成员不存在于地理位置集合中,返回
nil
。 GEOPOS
命令可以用于单个成员或多个成员的查询,允许一次性获取多个成员的坐标信息。
4.4 geodist(获取两个位置之间的直线距离)
GEODIST
是用于计算地理位置集合(GeoSet)中两个成员之间距离的命令。它能够返回成员之间的距离,单位默认为米(meters),或者可以通过选项指定为其他单位(如千米、英里等);<key>
: 地理位置集合(GeoSet)的键名。<member1>
: 第一个成员的名称。<member2>
: 第二个成员的名称。[unit]
: (可选)距离的单位,可选项包括:m
: 米(默认)km
: 千米mi
: 英里ft
: 英尺
ruby
GEODIST <key> <member1> <member2> [unit]
-
返回值:
如果两个成员都存在于地理位置集合中,
GEODIST
返回这两个成员之间的距离。如果其中一个或两个成员不存在于集合中,返回nil
。 -
假设有以下数据:
- 商店 A 的经纬度为 (13.361389, 38.115556)
- 商店 B 的经纬度为 (15.087269, 37.502669)
ruby
GEODIST stores "storeA" "storeB" km
这表示商店 A 和商店 B 之间的距离是 163.8964 千米:
ruby
127.0.0.1:6379> GEODIST stores "storeA" "storeB" km
"163.8964"
4.5 georadius(以给定的经纬度为中心,找出某一半径内的元素)
GEORADIUS
是 Redis 中用于根据给定的经纬度和半径查找地理位置元素的命令;
ruby
GEORADIUS key longitude latitude radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
ruby
- `key`: Redis 中存储地理位置数据的键名。
- `longitude` 和 `latitude`: 给定的中心点经纬度,用于确定搜索的中心。
- `radius`: 搜索半径,可以是以 `m` (米), `km` (千米), `ft` (英尺), `mi` (英里) 为单位的浮点数。
- `unit`: 单位参数,指定 `radius` 的单位,可以是 `m` (米), `km` (千米), `ft` (英尺), `mi` (英里)。
- `WITHCOORD`: 返回每个位置元素的经纬度。
- `WITHDIST`: 返回每个位置元素与中心点的距离。
- `WITHHASH`: 返回每个位置元素的 geohash 值。
- `COUNT count`: 指定返回的最大元素数量。
- `ASC|DESC`: 结果的排序方式,按距离升序或降序排列。
- `STORE key`: 将结果存储到指定键名的有序集合中。
- `STOREDIST key`: 将结果存储到指定键名的有序集合中,并且同时存储每个位置元素与中心点的距离。
- 假设我们有一个名为
stores
的 Redis 地理位置集合,其中存储了不同商店的经纬度信息。我们可以使用GEORADIUS
命令来查找以某一经纬度为中心,半径内的商店。- 例如,假设要查找以经度 13.361389 和纬度 38.115556 为中心,半径 2000 米内的商店,并返回商店的经纬度和距离:
- 这将返回半径 2000 米内所有商店的经纬度和它们与中心点的距离。
ruby
GEORADIUS stores 13.361389 38.115556 2000 m WITHCOORD WITHDIST
ruby
- 返回结果:
ruby
1) 1) "storeA"
2) 1) "13.36138933897018433"
2) "38.11555639549629859"
3) "100.0" // 与中心点的距离,单位由 WITHDIST 参数决定
2) 1) "storeB"
2) 1) "13.35622221279144287"
2) "38.12111264686523257"
3) "190.0"