Redis系列9:Geo 类型赋能亿级地图位置计算

Redis系列1:深刻理解高性能Redis的本质Redis系列2:数据持久化提高可用性Redis系列3:高可用之主从架构Redis系列4:高可用之Sentinel(哨兵模式)Redis系列5:深入分析Cluster 集群模式追求性能极致:Redis6.0的多线程模型追求性能极致:客户端缓存带来的革命Redis系列8:Bitmap实现亿万级数据计算
1 前言我们在第一篇 深刻理解高性能Redis的本质 的时候就介绍过Redis的几种基本数据结构,它是基于不同业务场景而设计的:

  • 动态字符串(REDIS_STRING):整数(REDIS_ENCODING_INT)、字符串(REDIS_ENCODING_RAW)
  • 双端列表(REDIS_ENCODING_LINKEDLIST)
  • 压缩列表(REDIS_ENCODING_ZIPLIST)
  • 跳跃表(REDIS_ENCODING_SKIPLIST)
  • 哈希表(REDIS_HASH)
  • 整数集合(REDIS_ENCODING_INTSET)除了这些常见数据类型 , 还有一些不常用的数据类型,如 BitMap、Geo、HyperLogLog 等等,他们在各自的方向为不同的类型的数据统计给出解决方案 。上一篇我们说了位图(BitMap)计算 , 可以应用于任何大数据场景下的二值计算,比如 是否登录、是否在线、是否签到、用户性别状态、IP黑名单、是否VIP用户统计 等等场景 。这一篇我们来介绍下Geo,分析它在 坐标记录、位置计算、距离计算上的能力,以及在地图业务中的应用场景 。
2 了解一下 Location Based ServicesLocation Based Services,记作 LBS,基于用户的地理位置数据定位展开的服务,广泛应用与地图类(百度地图、高德地图)、电商团购类(美团、饿了么)软件 。它常见的使用场景有:
  • 计算用户的精准的地理坐标位置
  • 统计用户定点坐标一定范围内的其他地理位置,并计算出距离
  • 对一定范围内的地理位置进行排序,并由近到远筛选
有没有感觉很熟悉,当然了,在我们的身边到处都是这样的应用场景 。
3 Geo所支持的能力Redis 的 GEO 特性在 Redis 3.2 版本就有了 ,  这个功能主要是用于存储用户地理位置信息 , 并对这些信息进行操作 。GEO 的数据结构总共有六个命令,我们一个个来介绍 :
  • geoadd
  • geopos
  • geodist
  • georadius
  • georadiusbymember
  • gethash
3.1 GEOADD 添加经纬信息Redis 提供了 GEOADD key longitude latitude member 命令,将一组经纬度信息和对应的所属对象的信息 记录到 GEO 类型的集合中,指令如下
GEOADD key longitude latitude member [longitude latitude member ...] longitude latitude member分别指给定的空间元素:维度、精度、名称 ,这些数据会以有序集合的形式存储在给定的键里面 。我们举个例子,如果你在地图上查找美食,那应该会出现一堆餐饮店铺和坐标位置,那他们的空间信息存储可能是这样的 。
redis> GEOADD food:location 115.775632 39.483256 "东北饺子馆" 114.081569 39.692756 "兰州拉面"(integer) 2
Redis系列9:Geo 类型赋能亿级地图位置计算

文章插图
3.2 GEOPOS 获取给定位置的经纬提供对应的键和位置名称,返回相应的经纬度信息 。
GEOPOS key member [member ...]按照上面的例子,我要获取对应的美食店位置坐标信息如下:
redis> GEOPOS food:location 东北饺子馆 兰州拉面 NonExisting "115.775632 39.483256" "114.081569 39.692756"3.3 GEODIST 返回给定两个位置距离很多时候 , 我们要导航去一个地方就会用到这类需求 。打开百度或者高德地图,起始位置就定位用户当前位置,目的地定位为搜索到的地址,比如上面的 东北饺子馆 。这时候地图软件需要计算出两个坐标之间的举例,来推荐用户是飞机高铁、开车、还是步行 。那么获取给定两个位置之间的距离就变得非常重要,GEODIST就是用来解决这个问题的 。
GEODIST key member1 member2 [unit]上述指令可以返回两个给定位置之间的距离,unit是距离单位 , 可选项,默认为m,枚举如下:
  • m:表示单位为米
  • km:表示单位为千米
  • mi:表示单位为英里
  • ft:表示单位为英尺
【Redis系列9:Geo 类型赋能亿级地图位置计算】需要注意的是如果两个位置之间的其中一个不存在, 那么会返回空值 。下面代码计算出东北饺子馆 和 兰州拉面 店铺之间的距离,大概是6.1公里 。
Redis系列9:Geo 类型赋能亿级地图位置计算

文章插图
redis> GEODIST food:location 东北饺子馆 兰州拉面"6184.15156"3.4GEORADIUS 获取给定经纬度的固定距离内的位置信息很多种应用场景是我登录了外卖APP,也确定了我自己所在的位置(即已确知经纬) , 需要获取一定距离范围内(比如10公里),所有的餐饮店 。这时候就使用到了 GEO 提供的 GEORADIUS指令了:根据输入的经纬度 , 查找以这个经纬度为中心的一定距离内的其他位置信息 。

推荐阅读