4

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

 1 year ago
source link: https://www.cnblogs.com/wzh2010/p/15886803.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

Redis系列1:深刻理解高性能Redis的本质
Redis系列2:数据持久化提高可用性
Redis系列3:高可用之主从架构
Redis系列4:高可用之Sentinel(哨兵模式)
Redis系列5:深入分析Cluster 集群模式
追求性能极致:Redis6.0的多线程模型
追求性能极致:客户端缓存带来的革命
Redis系列8:Bitmap实现亿万级数据计算

我们在第一篇 深刻理解高性能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 Services

Location 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
image

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:表示单位为英尺

需要注意的是如果两个位置之间的其中一个不存在, 那么会返回空值。下面代码计算出 东北饺子馆 和 兰州拉面 店铺之间的距离,大概是6.1公里。

image
redis> GEODIST food:location 东北饺子馆 兰州拉面
 
"6184.15156"

3.4 GEORADIUS 获取给定经纬度的固定距离内的位置信息

很多种应用场景是我登录了外卖APP,也确定了我自己所在的位置(即已确知经纬),需要获取一定距离范围内(比如10公里),所有的餐饮店。
这时候就使用到了 GEO 提供的 GEORADIUS指令了:根据输入的经纬度,查找以这个经纬度为中心的一定距离内的其他位置信息。

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count]
  • key longitude latitude: 是前置条件,给定的经纬度信息,以及我要搜索的key
  • radius :距离半径,指的搜索的范围
  • m|km|ft|mi: 为给定的距离单位,有 米、千米、英尺、英里 4种
  • [WITHCOORD] [WITHDIST] [WITHHASH]: 为返回的信息类型
    • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致。
    • WITHCOORD: 将位置元素的经度和维度也一并返回。
    • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。这个选项主要用于底层应用或者调试, 实际中的作用并不大。
  • ASC|DESC :可选参数,按照距离升序或者降序排列,即 由近到远(asc) 还是 由远到近(desc)
  • COUNT count:取数数量,避免获取到太多的信息,返回太多信息

所以如果需要获取 距离本人位置10公里半径内由近到远的美食店排序,按km单位计算,返回值带上距离信息,并只取前100个的信息,代码如下:

redis> GEORADIUS food:location 115.791331 39.5120003  10 km WITHDIST  ASC COUNT 100

"东北饺子馆"   3.3421
"兰州拉面"    9.4571

下图的绿色区域在固定半径(红圈)中搜索到了特定的几个目标位置:1、2、5、9、10。

image

3.5 GEORADIUSBYMEMBER 按照位置名称获取

GEORADIUS 的区别是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样,通过传入经度和纬度来决定中心点。
所以如下,已知兰州拉面和东北饺子馆的距离是6.1公里,根据兰州拉面获取10公里范围内的距离的美食店,可以获取到东北饺子馆和自己的位置:

redis> GEORADIUSBYMEMBER food:location "兰州拉面" 100 km WITHDIST

"东北饺子馆"   6.09127
"兰州拉面"    0

3.6 ZREM 删除关闭的店铺

redis>  ZREM food:location "兰州拉面"

(integer) 1
  • GEO 使用了 Sorted Set 集合类型,并通过 GeoHash 编码方法实现了经纬度到 Sorted Set 中元素权重分数的转换,涵盖两个关键能力就是就是对二维地图做区间划分,以及对区间进行编码。
  • 具体可应用的场景如下:
    • 计算用户的精准的地理坐标位置
    • 统计用户定点坐标一定范围内的其他地理位置,并计算出距离
    • 对一定范围内的地理位置进行排序,并由近到远筛选
  • 真实的地图数据存储,场景比这复杂的多,数据量会达到惊人的巨量,所以还是会使用分治原理进行拆分,细化到一个市甚至一个区,来提高存储和检索的效率。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK