Geospatial(地理空间)
在使用一些小程序的时候,里面通常都会通过定位使用者的位置,来显示附近的人、外卖距离、剩余路径等功能,在Redis3.2中也引入了推算地理信息的数据结构,即Geospatial
介绍
把某个具体的位置信息(经度,纬度,名称)添加到指定的key中,数据将会用一个sorted set存储,以便稍后能使用 GEORADIUS和 GEORADIUSBYMEMBER命令来根据半径来查询位置信息。
这个命令(指GEOADD)的参数使用标准的x,y形式,所以经度(longitude)必须放在纬度(latitude)之前,对于可被索引的坐标位置是有一定限制条件的:非常靠近极点的位置是不能被索引的, 在EPSG:900913 / EPSG:3785 / OSGEO:41001指定如下:
- 有效的经度是-180度到180度
- 有效的纬度是-85.05112878度到85.05112878度
上面是官方文档的描述,其实Geo并没有我们想象中的复杂,它的本质就是一个Zset,通过将坐标以Geohash的方式进行处理,将经度纬度错位后形成一个52位整数,所以我们同样能够使用Zset提供的接口来操作Geo。
用法
命令 | 作用 |
---|---|
GEOADD key 经度 纬度 地点名称 | 将指定的地理空间位置(经度、纬度、名称)添加到指定的key中 |
GEODIST key 地点1 地点2 | 返回两个给定位置之间的距离 |
GEOPOS key 地点 | 从key里返回所有给定位置元素的位置(经度和纬度) |
GEOHASH key 地点 | 返回一个或多个位置元素的 Geohash 表示 |
GEORADIUS key 经度 纬度 半径 | 以给定的经纬度为中心, 找出某一半径内的元素 |
GEORADIUSBYMEMBER key 地点 半径 | 找出位于指定范围内的元素,中心点是由给定的位置元素决定 |
Zset的接口同样适用于Geo,因此需要删除、查询全部时就可以使用Zset的接口。
下面示范一下这些命令的使用方式
# 为了方便示范,下面加入一些城市的地理信息——GEOADD
127.0.0.1:6379> GEOADD CHINA 108.94683 34.29296 "xian"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 116.405285 39.904989 "beijing"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 121.472644 31.231706 "shanghai"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 113.280637 23.125178 "guangzhou"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 114.085947 22.547 "shenzhen"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 110.33119 20.031971 "hainan"
(integer) 1
# 获取北京和上海的距离——GEODIST
127.0.0.1:6379> GEODIST CHINA beijing shanghai km
"1067.5980"
# 获取西安的坐标——GEOPOS
127.0.0.1:6379> GEOPOS CHINA xian
1) 1) "108.94683212041854858"
2) "34.29296115814533863"
# 以经度120 纬度35位置为中心,获取半径1000千米内的城市——GEORADIUS
127.0.0.1:6379> GEORADIUS CHINA 120 35 1000 km
1) "beijing"
2) "shanghai"
# 获取在广州半径500千米内的城市——GEORADIUSBYMEMBER
127.0.0.1:6379> GEORADIUSBYMEMBER CHINA guangzhou 500 km
1) "shenzhen"
2) "guangzhou"
3) "hainan"
# 将广州和深圳的坐标转换为11为的GEO哈希值——GEOHASH
127.0.0.1:6379> GEOHASH CHINA guangzhou shenzhen
1) "ws0e9cb3yj0"
2) "ws10k0dcg10"
Hyperloglog(基数统计)
在我们为网站统计访问量、日活量时,由于我们统计的是用户数量而非访问次数,因此即使一个用户多次访问也只会统计一次,这种不重复的数据通常被称为基数。
在传统的做法中,我们通常会采用set来保存用户的ID来进行计数,因为其本身存在着去重的功能,但是由于我们所需要的是对用户进行计数,如果通过将所有用户的ID保存的方法来完成,当用户量大的时候就会对内存产生巨大的压力,并且效率也大大降低。
为了解决这个问题,Redis在2.8.9版本添加了HyperLogLog结构。
介绍
Redis HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
在Redis 里面,每个HyperLogLog键只需要花费12KB内存,就可以计算接近2^64个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,由于HyperLogLog使用的是概率算法,通过存储元素的hash值的第一个1的位置,来计算元素数量,所以HyperLogLog 不会存储元素本身,在数据量大的时候也可能会存在一定的误差。但是在基数统计这一方面,它的效果是其他结构无法比拟的。
用法
命令 | 作用 |
---|---|
PFADD key value | 添加指定的值到Hyperloglog中 |
PFCONUT key | 返回给定Hyperloglog的基数估算值 |
PFMERGE destkey sourcekey | 将目标Hyperloglog合并到源Hyperloglog中 |
使用示范
127.0.0.1:6379> PFADD NUMS1 1 2 3 4 #向NUMS1插入1-4
(integer) 1
127.0.0.1:6379> PFADD NUMS1 1 #数据已存在,不再插入
(integer) 0
127.0.0.1:6379> PFCOUNT NUMS1 #查看当前基数数量
(integer) 4
127.0.0.1:6379> PFADD NUMS2 3 4 5 6 #向NUMS2插入3-6
(integer) 1
127.0.0.1:6379> PFMERGE NUMS1 NUMS2 #将NUMS2合并到NUMS1中
OK
127.0.0.1:6379> PFCOUNT NUMS1 #此时NUMS1中记录了1-6,六个元素
(integer) 6
Bitmap(位图)
介绍
位图其实就是哈希的变形,他通过哈希映射来处理数据,位图本身并不存储数据,而是存储标记。通过一个比特位,即0/1来标记一个数据的两种状态
位图通常情况下用在数据量庞大,且数据不重复的情景下标记某个数据的两种状态。 我们可以使用位图来记录当前用户的登陆情况、或者实现打卡、签到等功能。
用法
命令 | 作用 |
---|---|
GETBIT key offset value(0/1) | 设置Bitmap中偏移量为offset的位置的值 |
SETBIT key offset value | 返回Bitmap中偏移量为offset的位置的值 |
BITCOUNT key | 计算位图中有多少个1 |
127.0.0.1:6379> SETBIT TEST 1 1 #将位图中第1,3,5位设置为1
(integer) 0
127.0.0.1:6379> SETBIT TEST 3 1
(integer) 0
127.0.0.1:6379> SETBIT TEST 5 1
(integer) 0
127.0.0.1:6379> GETBIT TEST 1 #查看位图中1,2,3位的值
(integer) 1
127.0.0.1:6379> GETBIT TEST 2
(integer) 0
127.0.0.1:6379> GETBIT TEST 3
(integer) 1
127.0.0.1:6379> BITCOUNT TET #统计位图中1的数量,由于我们只设置了1,3,5位,因此为3
(integer) 3