首页 > 数据库 >Redis系列9:Geo 类型赋能亿级地图位置计算

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

时间:2022-11-03 14:47:38浏览次数:69  
标签:位置 Redis 距离 给定 亿级 拉面 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 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

4 总结

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

标签:位置,Redis,距离,给定,亿级,拉面,Geo,饺子馆
From: https://www.cnblogs.com/wzh2010/p/15886803.html

相关文章

  • Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua
    开心一刻我找了个女朋友,挺丑的那一种,她也知道自己丑,平常都不好意思和我一块出门昨晚,我带她逛超市,听到有两个人在我们背后小声嘀咕:“看咱前面,想不到这么丑都有人要。......
  • 1、ImageOps.equalize()方法
    1、导包fromPILimportImageOps 2、ImageOps.equalize使用直方图均衡化是一种增强图像对比度的方法,其主要思想是将一副图像的直方图分布变成近似均匀分布,从而......
  • 基于 Jetty9.4 的 GeoServer 配置与部署
    GeoServer2.16.exe安装包,默认使用Jetty发布地图服务。本篇介绍了通过jetty与GeoServer编译包geoserver.war发布地图服务。配置环境:windows10;jetty-distribution-......
  • [springboot, lettuce] io.lettuce.core.RedisCommandTimeoutException: Command time
    https://blog.csdn.net/zzhongcy/article/details/118935350?spm=1001.2101.3001.6650.7&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFr......
  • Windows系统Redis集群搭建
    一、参考网址https://mp.weixin.qq.com/s/ImdEJTdAmCFJsT55rici0Q二、Redis版本注意:搭建windows版的redis集群,redis的版本需要5.0及以上5.0版本redis下载地址:githhb下......
  • RedisTemplate自适应Redis配置模式config
    RedisTemplate配置Java源码:importcom.fasterxml.jackson.annotation.JsonAutoDetect;importcom.fasterxml.jackson.annotation.PropertyAccessor;importcom.fasterx......
  • Ubuntu上配置redis哨兵模式
    在Ubuntu上我使用的是APT命令安装Redis:sudoaptinstallredis,安装完成之后redis.conf的默认路径是:/etc/redis,redis-server的默认路径是:/usr/bin/redis-server假设我们有......
  • redis实现主从复制
     前面说到了redis在单机的模式下是可以数据持久化的,但是不可以解决单点失败的问题,当单台redis服务器出现问题时,就可能会造成数据的丢失;想要解决这个问题的话我们可以使用R......
  • 玩转Redis集群
    玩转Ridis集群Reids集群模式主从模式哨兵模式(Sentinel)Cluster模式一、主从模式ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅠ、直接配置运行Redis1.1master(主库)#......
  • 一线互联网大厂都是怎么面试Redis 审核中
    Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSIC编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库。随着Redis的热度越来越高......