GEO地理位置
简介
Redis
的
GEO
特性在
Redis 3.2
版本中推出, 这个功能可以将用户给定的地理位置信息储存起来, 并对
这些信息进行操作。来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。
geo
的数据类型为
zset
。
GEO
的数据结构总共有六个常用命令:
geoadd
、
geopos
、
geodist
、
georadius
、
georadiusbymember
、
gethash
官方文档:
https://www.redis.net.cn/order/3685.html
geoadd
解析:
# 语法geoadd key longitude latitude member ...# 将给定的空间元素 ( 纬度、经度、名字 ) 添加到指定的键里面。# 这些数据会以有序集 he 的形式被储存在键里面,从而使得 georadius 和 georadiusbymember 这样的命令可以在之后通过位置查询取得这些元素。# geoadd 命令以标准的 x,y 格式接受参数 , 所以用户必须先输入经度 , 然后再输入纬度。# geoadd 能够记录的坐标是有限的 : 非常接近两极的区域无法被索引。# 有效的经度介于 -180-180 度之间,有效的纬度介于 -85.05112878 度至 85.05112878 度之间。,当用户尝试输入一个超出范围的经度或者纬度时 ,geoadd 命令将返回一个错误。
测试:百度搜索经纬度查询,模拟真实数据
127 .0.0.1:6379> geoadd china:city 116 .23 40 .22 北京(integer) 1127 .0.0.1:6379> geoadd china:city 121 .48 31 .40 上海 113 .88 22 .55 深圳 120 .2130 .20 杭州(integer) 3127 .0.0.1:6379> geoadd china:city 106 .54 29 .40 重庆 108 .93 34 .23 西安 114 .0230 .58 武汉(integer) 3
geopos
解析:
# 语法geopos key member [member...]# 从 key 里返回所有给定位置元素的位置(经度和纬度)
测试:
127 .0.0.1:6379> geopos china:city 北京1 ) 1 ) "116.23000055551528931"2 ) "40.2200010338739844"127 .0.0.1:6379> geopos china:city 上海 重庆1 ) 1 ) "121.48000091314315796"2 ) "31.40000025319353938"2 ) 1 ) "106.54000014066696167"2 ) "29.39999880018641676"127 .0.0.1:6379> geopos china:city 新疆1 ) (nil)
geodist
解析:
# 语法geodist key member1 member2 [unit]# 返回两个给定位置之间的距离,如果两个位置之间的其中一个不存在 , 那么命令返回空值。# 指定单位的参数 unit 必须是以下单位的其中一个:# m表示单位为米# km表示单位为千米# mi表示单位为英里# ft表示单位为英尺# 如果用户没有显式地指定单位参数, 那么 geodist 默认使用米作为单位。#geodist 命令在计算距离时会假设地球为完美的球形 , 在极限情况下 , 这一假设最大会造成 0.5% 的误差。
测试:
127 .0.0.1:6379> geodist china:city 北京 上海"1088785.4302"127 .0.0.1:6379> geodist china:city 北京 上海 km"1088.7854"127 .0.0.1:6379> geodist china:city 重庆 北京 km"1491.6716"
georadius
解析:
# 语法georadius key longitude latitude radius m|km|ft|mi [withcoord][withdist][withhash][asc|desc][count count]# 以给定的经纬度为中心, 找出某一半径内的元素
测试:重新连接
redis-cli
,增加参数
--raw
,可以强制输出中文,不然会乱码
[root@ bin] # redis-cli --raw -p 6379# 在 china:city 中寻找坐标 100 30 半径为 1000km 的城市127 .0.0.1:6379> georadius china:city 100 30 1000 km重庆西安# withdist 返回位置名称和中心距离127 .0.0.1:6379> georadius china:city 100 30 1000 km withdist重庆635 .2850西安963 .3171# withcoord 返回位置名称和经纬度127 .0.0.1:6379> georadius china:city 100 30 1000 km withcoord重庆106 .5400001406669616729 .39999880018641676西安108 .9299985766410827634 .23000121926852302# withdist withcoord 返回位置名称 距离 和经纬度 count 限定寻找个数127 .0.0.1:6379> georadius china:city 100 30 1000 km withcoord withdist count1重庆635 .2850106 .5400001406669616729 .39999880018641676127 .0.0.1:6379> georadius china:city 100 30 1000 km withcoord withdist count2重庆635 .2850106 .5400001406669616729 .39999880018641676西安963 .3171108 .9299985766410827634 .23000121926852302
georadiusbymember
解析:
# 语法georadiusbymember key member radius m|km|ft|mi [withcoord][withdist][withhash][asc|desc][count count]# 找出位于指定范围内的元素,中心点是由给定的位置元素决定
测试:
127 .0.0.1:6379> GEORADIUSBYMEMBER china:city 北京 1000 km北京西安127 .0.0.1:6379> GEORADIUSBYMEMBER china:city 上海 400 km杭州上海
geohash
解析:
# 语法geohash key member [member...]# Redis 使用 geohash 将二维经纬度转换为一维字符串,字符串越长表示位置更精确 , 两个字符串越相似表示距离越近。
测试:
127 .0.0.1:6379> geohash china:city 北京 重庆wx4sucu47r0wm5z22h53v0127 .0.0.1:6379> geohash china:city 北京 上海wx4sucu47r0wtw6sk5n300
zrem
GEO
没有提供删除成员的命令,但是因为
GEO
的底层实现是
zset
,所以可以借用
zrem
命令实现对地理位置信息的删除
127 .0.0.1:6379> geoadd china:city 116 .23 40 .22 beijin1127 .0.0.1:6379> zrange china:city 0 -1 # 查看全部的元素重庆西安深圳武汉杭州上海beijin北京127 .0.0.1:6379> zrem china:city beijin # 移除元素1127 .0.0.1:6379> zrem china:city 北京 # 移除元素1127 .0.0.1:6379> zrange china:city 0 -1重庆西安深圳武汉杭州上海
HyperLogLog
简介
Redis
在
2.8.9
版本添加了
HyperLogLog
结构。
Redis HyperLogLog
是用来做基数统计的算法,
HyperLogLog
的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在
Redis
里面,每个
HyperLogLog
键只需要花费
12 KB
内存,就可以计算接近
2^64
个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
HyperLogLog
则是一种算法,它提供了不精确的去重计数方案。
举个栗子:假如我要统计网页的
UV
(浏览用户数量,一天内同一个用户多次访问只能算一次),传统的解决方案是使用
Set
来保存用户
id
,然后统计
Set
中的元素数量来获取页面
UV
。但这种方案只能承载少量
用户,一旦用户数量大起来就需要消耗大量的空间来存储用户
id
。我的目的是统计用户数量而不是保存
用户,这简直是个吃力不讨好的方案!而使用
Redis
的
HyperLogLog
最多需要
12k
就可以统计大量的用户
数,尽管它大概有
0.81%
的错误率,但对于统计
UV
这种不需要很精确的数据是可以忽略不计的。
什么是基数?
比如数据集
{1, 3, 5, 7, 5, 7, 8}
, 那么这个数据集的基数集为
{1, 3, 5 ,7, 8},
基数
(
不重复元素
)
为
5
。
基数估计就是在误差可接受的范围内,快速计算基数。
基本命令
命令
|
描述
|
---|---|
[PFADD key element [element ...]
|
添加指定元素到
HyperLogLog
中。
|
[PFCOUNT key [key ...]
|
返回给定
HyperLogLog
的基数估算值。
|
[PFMERGE destkey sourcekey
[sourcekey ...]
|
将多个
HyperLogLog
合并为一个
HyperLogLog
,并
集计算
|
测试
127.0 . 0.1 : 6379 > PFADD mykey a b c d e f g h i j1127.0 . 0.1 : 6379 > PFCOUNT mykey10127.0 . 0.1 : 6379 > PFADD mykey2 i j z x c v b n m1127.0 . 0.1 : 6379 > PFMERGE mykey3 mykey mykey2OK127.0 . 0.1 : 6379 > PFCOUNT mykey315
BitMap
简介
在开发中,可能会遇到这种情况:需要统计用户的某些信息,如活跃或不活跃,登录或者不登录;又如需要记录用户一年的打卡情况,打卡了是
1
, 没有打卡是
0
,如果使用普通的
key/value
存储,则要记录
365
条记录,如果用户量很大,需要的空间也会很大,所以
Redis
提供了
Bitmap
位图这中数据结构,
Bitmap
就是通过操作二进制位来进行记录,即为
0
和
1
;如果要记录
365
天的打卡情况,使用
Bitmap
表示的形式大概如下:
0101000111000111...........................
,这样有什么好处呢?当然就是节约内存
了,
365
天相当于
365 bit
,又
1
字节
= 8 bit ,
所以相当于使用
46
个字节即可。
BitMap
就是通过一个
bit
位来表示某个元素对应的值或者状态
,
其中的
key
就是对应元素本身,实际上底层也是通过对字符串的操作来实现。
Redis
从
2.2
版本之后新增了
setbit, getbit, bitcount
等几个
bitmap
相关命令。
setbit 设置操作
SETBIT key offffset value :
设置
key
的第
offffset
位为
value (1
或
0)
# 使用 bitmap 来记录上述事例中一周的打卡记录如下所示:# 周一: 1 ,周二: 0 ,周三: 0 ,周四: 1 ,周五: 1 ,周六: 0 ,周天: 0 ( 1 为打卡, 0 为不打卡)127 .0.0.1:6379> setbit sign 0 10127 .0.0.1:6379> setbit sign 1 00127 .0.0.1:6379> setbit sign 2 00127 .0.0.1:6379> setbit sign 3 10127 .0.0.1:6379> setbit sign 4 10127 .0.0.1:6379> setbit sign 5 00127 .0.0.1:6379> setbit sign 6 00
getbit 获取操作
GETBIT key offffset
获取
offffset
设置的值,未设置过默认返回
0
127 .0.0.1:6379> getbit sign 3 # 查看周四是否打卡1127 .0.0.1:6379> getbit sign 6 # 查看周七是否打卡0
bitcount 统计操作
bitcount key [start, end]
统计
key
上位为
1
的个数
# 统计这周打卡的记录,可以看到只有 3 天是打卡的状态:127 .0.0.1:6379> bitcount sign3