Redis 5 HyperLogLogs Bitmaps Geospatial
uwupu 啦啦啦啦啦

Redis 三种特殊类型

HyperLogLogs(基数统计)

用于统计一些准确度要求不高的数据;

  • 允许容错,可以接受一定误差;
  • 基数,指内容不可重复;A={1,2,3,4,5},B={3,5,6,7,9},基数=1,2,4,6,7,9;

用来做什么

可以用来统计各种计数,如注册IP数,每日访问IP数,在线用户数,共同好友数等;

优势

可以使用少量固定的内存去存储并识别集合中的唯一元素,估算的基数不一定准确,有0.81%标准错误近似值;

如:

一个IP消耗15个字节,100W个IP就是15M,HyperLogLog在Redis中每个键占用内容都是12K,理论存储近似接近2^64个值;不论存储的内容是什么,它有一个基于基数估算的算法,只能比较准确地估算出基数,可以使用少量固定的内存去存储并识别集合的唯一元素;

使用

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> pfadd k1 a b c d e f g h i  # k1 ={a,b,c,d,e,f,g,h,i}
(integer) 1
127.0.0.1:6379> pfcount k1 # 获取数量
(integer) 9
127.0.0.1:6379> pfadd k2 a z b x c s d r e # k2 = {a,b,c,d,e,z,x,s,r}
(integer) 1
127.0.0.1:6379> pfcount k2
(integer) 9
127.0.0.1:6379> pfmerge k3 k1 k2 # 合并k1和k2 存放到k3
OK
127.0.0.1:6379> pfcount k3 # k3的数量
(integer) 13

Bitmap(位存储)

位图数据结构,通过操作二进制数来进行记录,只有0和1两个状态;

用来做什么

比如用户每天的打卡情况;

设置打卡情况

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> setbit sign:year 0 1  # 用户第0天打卡了
(integer) 0
127.0.0.1:6379> setbit sign:year 1 0 # 用户第1天没打卡
(integer) 0
127.0.0.1:6379> setbit sign:year 2 1 # 用户第二天打卡了
(integer) 0
127.0.0.1:6379> setbit sign:year 3 1
(integer) 0
127.0.0.1:6379> setbit sign:year 4 0 # 用户第4天没打卡
(integer) 0

获取打卡情况

1
2
3
4
127.0.0.1:6379> getbit sign:year 4  # 用户第4天没打卡
(integer) 0
127.0.0.1:6379> getbit sign:year 3 # 用户第三天打卡了
(integer) 1

获取所有的打卡情况

1
2
127.0.0.1:6379> bitcount sign:year
(integer) 3

Geospatial(地理位置)

geospatial可以存放一个坐标,地理位置,基于经纬度;

底层实现原理

Geo的底层实现就是SortedSet,可以通过SortedSet命令控制geo;

原理

Redis Geo使用Geohash实现位置的存储;

Geohash将经纬度编码成为一个52bit的整型,而此时有序集合的score就可以存储52bit的整型且不失精度;

一些命令

geoadd 添加地理位置

介绍

GEOADD key [NX | XX] [CH] longitude latitude member [longitude latitude member ...]

添加指定的位置信息到key中;

数据存储为一个有序集合;

可以通过GEOSEARCH命令获取这些信息;

参数

longitude 经度 latitude 纬度

命令支持标准的x,y坐标,经度必须放置在纬度的前面;

极其接近极点的坐标无法被索引:

  • 有效经度范围:-180到180;
  • 有效纬度范围:-85.05112878到85.05112878

若使用范围之外的经纬度会返回错误;

XX

仅更新已有元素,不添加新元素;

NX

不更新已有元素,只添加新元素;

CH

GEOADD默认返回值为新添加的元素的数量,使用CH之后将返回值改为改变的元素的数量,不计入原值和输入值相同的情况。一个双score有序集合可以存储一个52bit的整数且不失精度;

注意:XX与NX不可一起使用

geopos 获取指定成员经纬度

GEOPOS key member [member ...]

返回所有指定成员的经度和纬度;

通过key使用有序集合进行索引;

由于存储数据时采用geohash方法,获取到的数据可能会出现一些误差;

若元素不存在则返回一个由null组成的数组;

1
2
3
4
5
6
7
8
127.0.0.1:6379> geoadd g1 116 40 "BeiJing" 112 37 "TaiYuan"  # 添加TaiYuan和BeiJing的经纬度
(integer) 2
127.0.0.1:6379> GEOPOS g1 BeiJing TaiYuan NonExistMember # 查询TaiYuan和BeiJing还有一个没有输入的值的经纬度
1) 1) "116.00000113248825073"
2) "39.99999991084916218"
2) 1) "112.00000137090682983"
2) "37.00000026605963654"
3) (nil) # member不存在,返回nil

geodist 两个成员的距离

GEODIST key member1 member2 [M | KM | FT | MI]

返回两个成员之间的距离;

如果有一个或两个成员不存在,则返回null;

最后的参数为单位,默认为米:

  • m 米;
  • km 千米;
  • mi 英里;
  • ft 尺 步数

距离的计算基于假定地球是一个完美的球体,所以计算结果会有0.5%的误差;

1
2
3
4
5
6
7
127.0.0.1:6379> GEOPOS g1 BeiJing TaiYuan
1) 1) "116.00000113248825073"
2) "39.99999991084916218"
2) 1) "112.00000137090682983"
2) "37.00000026605963654"
127.0.0.1:6379> GEODIST g1 BeiJing TaiYuan m
"482157.6407"

geohash

GEOHASH key member [memebr …]

返回geohash字符串

(geohash是一个可以将纬度和精度编码为一个52bit的散列函数)

1
2
3
127.0.0.1:6379> GEOHASH g1 BeiJing TaiYuan
1) "wx47x9u8gu0"
2) "wqxdkxeut50"

geosearch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GEOSEARCH key 
<
FROMMEMBER member |
FROMLONLAT longitude latitude
> # 二选一 从成员 从经纬度
<
BYRADIUS radius <M | KM | FT | MI> |
BYBOX width height <M | KM | FI | MI>
> # 通过圆形 通过矩形
[ASC | DESC]
[COUNT count [ANY]]
[WITHCOORD]
[WITHDIST]
[WITHHASH]
介绍

返回给定形状范围内的member列表;

支持搜索圆形区域和方形取悦;

命令代替了GEORADIUS和GEORADIUSBYMEMBER;

参数

形状的中心

FROMMEMBER:以成员为形状的原点;

FROMLONLAT:以指定经纬度为形状的原点;

形状的参数

BYRADIUS:形状为圆形,根据给定radius参数为圆形的半径

BYBOX:形状为矩形,根据给定的width和height为形状的长宽;

需要返回对象的其他参数

WITHDIST:返回原点到各个成员的距离;

WITHCOORD:返回成员的经纬度;

WITHHASH:返回成员的GEOHASH值。

是否排序

若未指定以下两个参数,则默认不排序;

ASC:排序顺序为距离原点,最近的元素到最远的元素;

DESC:距离原点,最远的元素到最近的元素;

返回数量

COUNT <count> [ANY]

默认返回所有的元素;

通过COUNT <count>参数可以限制返回的数量;

若提供ANY,Redis查询过程会在查到指定数量的结果后直接返回不排序,且不考虑远近问题;

若不提供ANY,Redis会返回排序后的所有结果。不提供ANY时,命令执行的速度会相对慢一点;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> GEODIST g1 BeiJing TaiYuan m # 查询得知,TaiYuan到BeiJing的距离为482157m,换算48.22km
"482157.6407"
127.0.0.1:6379> GEOSEARCH g1 FROMMEMBER TaiYuan BYRADIUS 500 KM ASC COUNT 2 WITHCOORD WITHDIST WITHHASH
# 查询g1中 以TaiYuan为圆心,半径为500KM,两个对象, 要求返回结果中有距离圆心的距离、对象的经纬度还有对象的GEOHASH
1) 1) "TaiYuan"
2) "0.0000"
3) (integer) 4041790908459398
4) 1) "112.00000137090682983"
2) "37.00000026605963654"
2) 1) "BeiJing"
2) "482.1576"
3) (integer) 4069855081124858
4) 1) "116.00000113248825073"
2) "39.99999991084916218"

geosearchstore

1
2
3
4
5
6
7
8
9
10
11
12
GEOSEARCHSTORE destination source
<
FROMMEMBER member | # 原点为对象
FROMLONLAT logitude latitude # 原点为经纬度
>
<
BYRADIUS radius <M | KM | FT |MI> | # 圆,半径,单位
BYBOX width height <M | KM | FT | MI> # 矩形,宽,高,单位
>
[ASC | DESC] # 从近到远 从远到近
[COUNT count [ANY]] # 数量 ANY任意对象
[STOREDIST] #

与GEOSEARCH类似;

不同的是,GEOSEARCHSTORE会将获得的结果存放到destination中;

默认将获得的对象以及其GEOHASH以SortedSet方式存放;

使用STOREDIST参数后,存放内容为获得的对象和距离原点的距离

STOREDIST,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> GEOSEARCHSTORE ss1 g1 FROMMEMBER BeiJing BYRADIUS 500 KM ASC COUNT 2 ANY
(integer) 2
127.0.0.1:6379> GEOSEARCHSTORE ss2 g1 FROMMEMBER BeiJing BYRADIUS 500 KM ASC COUNT 2 ANY STOREDIST
(integer) 2
127.0.0.1:6379> zrange ss1 0 -1 WITHSCORES
1) "TaiYuan"
2) "4041790908459398"
3) "BeiJing"
4) "4069855081124858"
127.0.0.1:6379> zrange ss2 0 -1 WITHSCORES
1) "BeiJing"
2) "0"
3) "TaiYuan"
4) "482.15764068388631"

georadius 通过半径获取附近的人的地址(弃用)

GEORADIUS key longitud latitude raduis <M | KM | FI | MI> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key] [STOREDIST key]

georadiusbymember 通过半径获取成员附近的地址(弃用)

1
2
3
GEORADIUSBYMEMBER key member radius <M | KM | FT | MI> [WITHCOORD]
[WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key]
[STOREDIST key]

 评论