geospatial(地理位置)

可以先查询一些测试数据:https://jingweidu.bmcx.com/

城市 经度 纬度
北京 116.40 39.90
上海 121.47 31.23
重庆 106.50 29.53
深圳 114.05 22.52
杭州 120.16 30.24

只有六个命令:

geoadd

将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。

该命令以采用标准格式的参数x,y,所以经度必须在纬度之前。这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:

  • 有效的经度从-180度到180度。
  • 有效的纬度从-85.05112878度到85.05112878度。

当坐标位置超出上述指定范围时,该命令将会返回一个错误。

##geoadd:添加地理位置
#参数:key 经度 纬度 名称
## 一般不会手动添加数据,而是下载城市数据,使用java程序一次性导入

127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 114.05 22.52 shenzhen 120.16 30.24 hangzhou
(integer) 2
127.0.0.1:6379> 

geopos

geopos:获得当前定位

## 获取指定城市的经纬度
127.0.0.1:6379> geopos china:city beijing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city shanghai chongqing
1) 1) "121.47000163793563843"
   2) "31.22999903975783553"
2) 1) "106.49999767541885376"
   2) "29.52999957900659211"
127.0.0.1:6379> geopos china:city shenzhen hangzhou
1) 1) "114.04999762773513794"
   2) "22.5200000879503861"
2) 1) "120.1600000262260437"
   2) "30.2400003229490224"
127.0.0.1:6379> 

geodist

返回两个给定位置之间的距离。

如果两个位置之间的其中一个不存在, 那么命令返回空值。

指定单位的参数 unit 必须是以下单位的其中一个:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。

GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。

127.0.0.1:6379> geodist china:city beijing  shanghai#北京到上海的距离(单位:m)
"1067378.7564"
127.0.0.1:6379> geodist china:city beijing  shanghai km#北京到上海的距离(单位:km)
"1067.3788"
127.0.0.1:6379> geodist china:city beijing  louzhou #以为兰州没有录入,所以返回nil
(nil)
127.0.0.1:6379> 

georadius

以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

范围可以使用以下其中一个单位:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。

在给定以下可选项时, 命令会返回额外的信息:

  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。

命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:

  • ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。
  • DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。

在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。 虽然用户可以使用 COUNT `` 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。

# 在china:city中查找以经纬度110,30的点为中心,半径为1000km范围内的所有城市
127.0.0.1:6379> georadius china:city 110 30  1000 km
1) "chongqing"
2) "shenzhen"
3) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30  1000 km withcoord
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "shenzhen"
   2) 1) "114.04999762773513794"
      2) "22.5200000879503861"
3) 1) "hangzhou"
   2) 1) "120.1600000262260437"
      2) "30.2400003229490224"
127.0.0.1:6379> georadius china:city 110 30  1000 km count 2#限定返回元素数量
1) "chongqing"
2) "shenzhen"
127.0.0.1:6379> 

georadiusbymember

这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点

指定成员的位置被用作查询的中心。

#在china:city中查询以上海为中心,方圆1000km内的城市
127.0.0.1:6379> georadiusbymember china:city shanghai 1000 km 
1) "hangzhou"
2) "shanghai"
127.0.0.1:6379> georadiusbymember china:city shanghai 1000 km withcoord withdist withhash
1) 1) "hangzhou"
   2) "166.7613"
   3) (integer) 4054133997236782
   4) 1) "120.1600000262260437"
      2) "30.2400003229490224"
2) 1) "shanghai"
   2) "0.0000"
   3) (integer) 4054803462927619
   4) 1) "121.47000163793563843"
      2) "31.22999903975783553"
127.0.0.1:6379> 

geohash(了解即可)

返回一个或多个位置元素的 Geohash 表示。

通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash,在维基百科geohash.org网站都有相关描述

该命令将返回11个字符的Geohash字符串,所以没有精度Geohash,损失相比,使用内部52位表示。返回的geohashes具有以下特性:

  1. 他们可以缩短从右边的字符。它将失去精度,但仍将指向同一地区。
  2. 它可以在 geohash.org 网站使用,网址 http://geohash.org/。查询例子:http://geohash.org/sqdtr74hyu0.
  3. 与类似的前缀字符串是附近,但相反的是不正确的,这是可能的,用不同的前缀字符串附近。
##将二维的经纬度转换为一维的字符串
127.0.0.1:6379> geohash china:city beijing shanghai hangzhou
1) "wx4fbxxfke0"
2) "wtw3sj5zbj0"
3) "wtmkn31bfb0"
127.0.0.1:6379> 

geo 底层原理

geo的底层实现原理其实就是sorted set(Zset)!我们可以用zset的命令操作geo。

127.0.0.1:6379> zrange china:city 0 -1 #查看china:city中的所有城市
1) "chongqing"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
5) "beijing"
127.0.0.1:6379> zrem china:city beijing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1 #移除北京
1) "chongqing"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
127.0.0.1:6379> 

Hyperloglog

Redis 在 2.8.9 版本添加了 HyperLogLog 结构,是一种数据结构。

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

什么是基数?

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素的个数)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

序号 命令及描述
1 [PFADD key element element …] 添加指定元素到 HyperLogLog 中。
2 [PFCOUNT key key …] 返回给定 HyperLogLog 的基数估算值。
3 [PFMERGE destkey sourcekey sourcekey …] 将多个 HyperLogLog 合并为一个 HyperLogLog
127.0.0.1:6379> pfadd k1 1 2 3 4
(integer) 1
127.0.0.1:6379> pfcount k1 #k1的基数
(integer) 4
127.0.0.1:6379> pfadd k2 3 4 5 6
(integer) 1
127.0.0.1:6379> pfcount k2 #k2的基数
(integer) 4
127.0.0.1:6379> pfmerge k3 k1 k2#将k1和k2合并为k3
OK
127.0.0.1:6379> pfcount k3 #k3的基数
(integer) 6
127.0.0.1:6379> 
#k1:{1,2,3,4}    k2:{3,4,5,6}
#k3:{1,2,3,3,4,4,5,6}  k3的基数集为:{1,2,3,4,5,6} 所以基数等于 6

Bitmaps

位存储(0,1)

bitmaps的使用范围很广,在统计用户信息:用户状态(活跃和不活跃),登录和未登录,打卡和未打卡,这种两个状态的信息,都可以使用bitmaps

bitmaps位图是一种数据结构,都是操作二进制来进行记录的,就只有0和1两个状态。

测试

#统计一周的打卡天数
#比如:用0-6表示周日到周六   0标识未打卡  1标识打卡
127.0.0.1:6379> setbit sign 0  1
(integer) 0
127.0.0.1:6379> setbit sign 1  0
(integer) 0
127.0.0.1:6379> setbit sign 2  0
(integer) 0
127.0.0.1:6379> setbit sign 3  1
(integer) 0
127.0.0.1:6379> setbit sign 4  0
(integer) 0
127.0.0.1:6379> setbit sign 5  1
(integer) 0
127.0.0.1:6379> setbit sign 6  0
(integer) 0

127.0.0.1:6379> getbit sign 3 #查看周三是否打卡
(integer) 1
127.0.0.1:6379> bitcount sign#统计这周的打卡次数 
(integer) 3