Redis实现Gaospatial地理位置操作

576 阅读5分钟

这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战

今日学习内容

在上一篇的文章中我们讲解了在Redis中五大数据类型的基本使用,但是在Redis中其实还有三种非常实用的特殊数据类型,分别是Gaospatial地理位置、Hyperloglog基数统计、Bitmap位图场景, 这三种特殊数据类型主要是对应了三种不同的使用场景。

所以接下来的几篇文章主要来和大家讲解一下这三种特殊数据类型的基本命令以及使用场景,保证你学习完之后颇有收获!!!

Gaospatial地理位置

百度地图、高德地图这些地图软件大家应该都用过吧?输入两个位置,我们就可以得到两个位置之间的距离。或者你想要查询你附近500米以内的超市,那么你直接点击范围就可以。还有我们QQ、微信、玩游戏的时候的附近的人的查询你都可以查询得到。

而这些操作,在Redis的Gaospatial地理位置中都可以实现!

首先在课程开始之前先给大家推荐一个查询全国城市经纬度的网站,下面的学习中需要查询某个城市经纬度的话可以直接来这里查询:

城市经纬度查询-国内城市经度纬度在线查询工具 http://www.jsons.cn/lngcode/

添加一个或多个地理位置的坐标

在地图中,如果我们想要查询一个位置,那么其实都是依据这个位置的坐标来实现的,所以在查询之前,一定是需要先将这个坐标输入的对吧,Redis的Gaospatial中添加地理位置坐标的命令是GEOADD,格式如下:

GEOADD key longitude latitude member [longitude latitude member ...]

  • key为该地理位置的索引
  • longitude表示该位置的经度
  • latitude表示该位置的纬度
  • member表示地名
  • [longitude latitude member ...]表示可以重复添加,中间以空格分隔

为了方便下面的命令的使用,建议大家在这一步多输入几个城市的经纬度,

比如我们查询深圳的经纬度为:114.085947(经度),22.547(纬度),

并且深圳是中国的城市,那么我们可以定义深圳的索引key是“china:city”,longitude是“114.08”,latitude是“22.54”,member是“shenzhen”,输入的命令就是这样的:

127.0.0.1:6379> GEOADD china:city 114.08 22.54 shenzhen
(integer) 1

注意:Gaospatial地理位置中,多个城市可以使用同一个key,比如“shenzhen”和“xian”的key都可以是“china:city”,我们在查询的时候可以通过索引+地名的形式查询,就像我们上面讲的Hash数据类型是一样的,

现在多输入几个城市:

127.0.0.1:6379> GEOADD china:city 114.08 22.54 shenzhen
(integer) 1
127.0.0.1:6379> GEOADD china:city 116.10 39.90 beijing
(integer) 1
127.0.0.1:6379> GEOADD china:city 113.66 34.75 zhengzhou
(integer) 1
127.0.0.1:6379> GEOADD china:city 112.54 37.85 taiyuan
(integer) 1
127.0.0.1:6379> GEOADD china:city 113.28 23.12 guangzhou
(integer) 1
127.0.0.1:6379>  GEOADD china:city 120.15 30.28 hangzhou 118.76 32.04 nanjing
(integer) 2

注意在输入经纬度的时候,数据是可以任意保留小数位的,而且现在虽然是一个一个写入,但是在开发的实际操作中,我们可以通过读取数据库直接写入。

查询一个或多个地理位置坐标

上面我们已经插入了很多条地理位置的数据,现在我们可以通过GEOPOS命令来获取指定地理位置的坐标,格式如下:

GEOPOS key member [member ...]

  • key表示输入时该地理位置的索引
  • member表示地理位置的名称,可以输入多个中间以空格分开

如我们要查询郑州、北京和长沙的地理坐标,(但是长沙的不存在,则返回null)

127.0.0.1:6379> GEOPOS china:city zhengzhou
1) 1) "113.65999907255172729"
   2) "34.74999926510690784"
127.0.0.1:6379> GEOPOS china:city beijing changsha
1) 1) "116.09999924898147583"
   2) "39.90000009167092543"
2) (nil)

查询两地之间的距离

在地图中我们经常会查询两个地方之间的距离,或者在微信中实时共享两个人的位置坐标,这个时候都是需要查询两个地方的距离来实现的,在Redis中查询两个地方距离的命令是:

GEODIST key member1 member2 [unit]

  • key为要查询的两个地理位置的索引,注意两个地理位置需要使用同一个索引,
  • member1为第一个位置名称
  • member2为第二个位置名称
  • [unit]为显示的单位,可以是m(米,默认)、km(千米)、ft(英尺)、mi(英里)

如我们查询郑州到杭州的直线距离,以米为单位,

127.0.0.1:6379> GEODIST china:city zhengzhou hangzhou
"785609.9719"
127.0.0.1:6379> GEODIST china:city zhengzhou hangzhou m
"785609.9719"

再查询深圳到北京的直线距离:

127.0.0.1:6379> GEODIST china:city shenzhen beijing km
"1940.2709"

查询到的结果是1940.2709km,我们百度验证一下:

查询到的结果稍微有一点误差,但是可以接受,产生误差的原因可能是输入的经纬度的精度问题,或者是百度和Redis定位的市中心的位置不一样都有可能。

以坐标为中心来范围搜索地理位置

我们平常都会使用到附近的人功能,或者以自己为中心搜索附近,Redis中可以使用命令GEORADIUS来指定附近多少米以内的地理位置的查询。

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]

  • key为要查询的地理位置的索引
  • longitude为该地理位置的经度
  • latitude为该地理位置的纬度
  • radius表示要查询的半径
  • m|km|ft|mi表示单位
  • [WITHCOORD]可选,表示是否输出经纬度
  • [WITHDIST]可选,表示是否输出距离
  • [WITHHASH]可选,表示是否输出哈希值
  • [COUNT count]可选,表示输出几个数据
  • [ASC|DESC]可选,表示按照距离升序还是降序排列,ASC升序,DESC降序

比如我们查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1000 km
1) "shenzhen"
2) "guangzhou"

查询到的结果是深圳和广州,注意:只有我们输入的坐标才会被查询出来,没有输入的不会查询出来!

下面我们多看几个实例:

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,同时输出地理位置的坐标:

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,同时输出距离:

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1500 km WITHCOORD
1) 1) "shenzhen"
   2) 1) "114.08000081777572632"
      2) "22.53999903789756587"
2) 1) "guangzhou"
   2) 1) "113.27999979257583618"
      2) "23.1199990030198208"
3) 1) "hangzhou"
   2) 1) "120.15000075101852417"
      2) "30.2800007575645509"
4) 1) "zhengzhou"
   2) 1) "113.65999907255172729"
      2) "34.74999926510690784"
5) 1) "nanjing"
   2) 1) "118.75999957323074341"
      2) "32.03999960287850968"

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,同时输出距离:

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1500 km WITHDIST
1) 1) "shenzhen"
   2) "3.8011"
2) 1) "guangzhou"
   2) "103.3692"
3) 1) "hangzhou"
   2) "1055.1042"
4) 1) "zhengzhou"
   2) "1360.8264"
5) 1) "nanjing"
   2) "1156.3230"

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,但只输出两个:

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1500 km COUNT 2
1) "shenzhen"
2) "guangzhou"

以位置为中心来范围搜索地理位置

上面我们是以坐标的形式来进行范围搜索的,还有一种方式是以位置为中心进行搜索,这种的可以用于输入一个确定的地理位置进行范围搜索,这个命令和上面利用坐标进行范围搜索的使用方法基本一样,命令格式如下:

GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]

  • key为要查询的地理位置的索引
  • member为要作为中心点的地理位置
  • radius表示要查询的半径
  • m|km|ft|mi表示单位
  • [WITHCOORD]可选,表示是否输出经纬度
  • [WITHDIST]可选,表示是否输出距离
  • [WITHHASH]可选,表示是否输出哈希值
  • [COUNT count]可选,表示输出几个数据
  • [ASC|DESC]可选,表示按照距离升序还是降序排列,ASC升序,DESC降序

如我们查询以太原为中心,800km以内的城市:

127.0.0.1:6379> GEORADIUSBYMEMBER china:city taiyuan 800 km
1) "zhengzhou"
2) "taiyuan"
3) "beijing"

以上就是Redis中的Gaospatial地理位置操作,主要一般是用于地图应用。下期我们将讲解如何进行Hyperloglog基数统计操作。

我是灰小猿,我们下期见