搜索“附近的餐馆”、在打车软件上叫车,这些都离不开基于位置信息服务(Location-Based Service,LBS)的应用。LBS 应用访问的数据是和人或物关联的一组经纬度信息,而且要能查询相邻的经纬度范围

  • 以叫车服务为例,来分析下 LBS 应用中经纬度的存取特点。
  1. 每一辆网约车都有一个编号(例如 33),网约车需要将自己的经度信息(例如 116.034579)和纬度信息(例如 39.000452 )发给叫车应用。
  2. 用户在叫车的时候,叫车应用会根据用户的经纬度位置(例如经度 116.054579,纬度 39.030452),查找用户的附近车辆,并进行匹配。
  3. 等把位置相近的用户和车辆匹配上以后,叫车应用就会根据车辆的编号,获取车辆的信息,并返回给用户。

可以看到,一辆车(或一个用户)对应一组经纬度,并且随着车(或用户)的位置移动,相应的经纬度也会变化。

使用hash进行key:车辆ID,value:车辆经纬度

这种数据记录模式属于一个 key(例如车 ID)对应一个 value(一组经纬度)。当有很多车辆信息要保存时,就需要有一个集合来保存一系列的 key 和 value。Hash 集合类型可以快速存取一系列的 key 和 value,正好可以用来记录一系列车辆 ID 和经纬度的对应关系,所以,我们可以把不同车辆的 ID 和它们对应的经纬度信息存在 Hash 集合中,如下图所示:

Hash 类型的 HSET 操作命令,会根据 key 来设置相应的 value 值,所以,我们可以用它来快速地更新车辆变化的经纬度信息。

问题:

对于一个 LBS 应用来说,除了记录经纬度信息,还需要根据用户的经纬度信息在车辆的 Hash 集合中进行范围查询。一旦涉及到范围查询,就意味着集合中的元素需要有序,但 Hash 类型的元素是无序的,显然不能满足我们的要求。

Sorted Set类型进行记录

GEO 类型的底层数据结构就是用 Sorted Set 来实现的

Sorted Set 类型也支持一个 key 对应一个 value 的记录模式,其中,key 就是 Sorted Set 中的元素,而 value 则是元素的权重分数。更重要的是,Sorted Set 可以根据元素的权重分数排序,支持范围查询。这就能满足 LBS 服务中查找相邻位置的需求了。

用 Sorted Set 来保存车辆的经纬度信息时,Sorted Set 的元素是车辆 ID,元素的权重分数是经纬度信息,如下图所示:


Sorted Set 元素的权重分数是一个浮点数(float 类型),而一组经纬度包含的是经度和纬度两个值,是没法直接保存为一个浮点数的,那具体该怎么进行保存呢?

  • GEO 类型中的 GeoHash 编码

Redis 采用了业界广泛使用的 GeoHash 编码方法,这个方法的基本原理就是“二分区间,区间编码”

对于一个地理位置信息来说,它的经度范围是[-180,180]。GeoHash 编码会把一个经度值编码成一个 N 位的二进制值,我们来对经度范围[-180,180]做 N 次的二分区操作,其中 N 可以自定义。

在进行第一次二分区时,经度范围[-180,180]会被分成两个子区间:[-180,0) 和[0,180](我称之为左、右分区)。此时,我们可以查看一下要编码的经度值落在了左分区还是右分区。如果是落在左分区,我们就用 0 表示;如果落在右分区,就用 1 表示。这样一来,每做完一次二分区,我们就可以得到 1 位编码值。

然后,我们再对经度值所属的分区再做一次二分区,同时再次查看经度值落在了二分区后的左分区还是右分区,按照刚才的规则再做 1 位编码。当做完 N 次的二分区后,经度值就可以用一个 N bit 的数来表示了。

举个例子,假设我们要编码的经度值是 116.37,我们用 5 位编码值(也就是 N=5,做 5 次分区)。

我们先做第一次二分区操作,把经度区间[-180,180]分成了左分区[-180,0) 和右分区[0,180],此时,经度值 116.37 是属于右分区[0,180],所以,我们用 1 表示第一次二分区后的编码值。

接下来,我们做第二次二分区:把经度值 116.37 所属的[0,180]区间,分成[0,90) 和[90, 180]。此时,经度值 116.37 还是属于右分区[90,180],所以,第二次分区后的编码值仍然为 1。等到第三次对[90,180]进行二分区,经度值 116.37 落在了分区后的左分区[90, 135) 中,所以,第三次分区后的编码值就是 0。

按照这种方法,做完 5 次分区后,我们把经度值 116.37 定位在[112.5, 123.75]这个区间,并且得到了经度值的 5 位编码值,即 11010。这个编码过程如下表所示:

对纬度的编码方式,和对经度的一样,只是纬度的范围是[-90,90],下面这张表显示了对纬度值 39.86 的编码过程。

当一组经纬度值都编完码后,我们再把它们的各自编码值组合在一起,组合的规则是:最终编码值的偶数位上依次是经度的编码值,奇数位上依次是纬度的编码值,其中,偶数位从 0 开始,奇数位从 1 开始。

我们刚刚计算的经纬度(116.37,39.86)的各自编码值是 11010 和 10111,组合之后,第 0 位是经度的第 0 位 1,第 1 位是纬度的第 0 位 1,第 2 位是经度的第 1 位 1,第 3 位是纬度的第 1 位 0,以此类推,就能得到最终编码值 1110011101,如下图所示:

当然,使用 GeoHash 编码后,我们相当于把整个地理空间划分成了一个个方格,每个方格对应了 GeoHash 中的一个分区。

【Redis】数据结构的应用——GEO 【搜索“附近的餐馆”、在打车软件上叫车】相关推荐

  1. Redis核心技术笔记——Redis数据结构

    Redis底层数据结构 ​ 总体来说,大家都知道redis数据结构有String.List.Hash.Set.Sorted Set还有三种高级的数据结构Bit map.GEO.Hyperloglog. ...

  2. Redis数据实战之GEO在LBS中应用与自定义新数据类型

    Redis数据实战之GEO在LBS中应用与自定义新数据类型 引言 面向 LBS 应用的 GEO 数据类型 GEO 的底层结构 GeoHash 的编码方法 如何操作 GEO 类型 如何自定义数据类型 R ...

  3. Redis数据结构以及对应存储策略

    redis数据结构: String 可以是字符串也可以是数字,以及浮点数 List,一个链表,链表上每一个节点都包含一个字符串 set 包含字符串的无序手机其,特点是每一个字符都是唯一的 hash,包 ...

  4. redis 经纬度_【SpringBoot DB 系列】Redis 高级特性之 GEO

    [SpringBoot DB 系列]Redis 高级特性之 GEO GEO 用于存储地理信息,最直观的就是我们日常使用的地图 app 中,如果我想查询我所在地的周边餐饮,就可以利用 geo 中的以(x ...

  5. Redis数据结构与参数调优

    一.Redis基础入门 1.Redis 简介 Redis是一种高级key-value数据库.它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富.有字符串,链表.哈希.集合和有序集 ...

  6. Redis 数据结构与内存管理策略(上)

    Redis 数据结构与内存管理策略(上) 标签: Redis Redis数据结构 Redis内存管理策略 Redis数据类型 Redis类型映射 Redis 数据类型特点与使用场景 String.Li ...

  7. 笔记【Redis数据结构、常用命令、key淘汰及持久化策略】

    文章目录 简要介绍 服务安装 数据结构 通用命令 字符串类型命令 散列类型命令 列表类型命令 集合类型命令 有序集合类型命令 HyperLogLog命令 GeoHash命令(地图坐标) 排序命令 事务 ...

  8. Redis 数据结构-字典源码分析

    2019独角兽企业重金招聘Python工程师标准>>> 相关文章 Redis 初探-安装与使用 Redis 数据结构-字符串源码分析 本文将从以下几个方面介绍 前言 字典结构图 字典 ...

  9. 为了拿捏 Redis 数据结构,我画了 40 张图

    Redis 为什么那么快? 除了它是内存数据库,使得所有的操作都在内存上进行之外,还有一个重要因素,它实现的数据结构,使得我们对数据进行增删查改操作时,Redis 能高效的处理. 因此,这次我们就来好 ...

最新文章

  1. 远哥教你MuleESB系列视频教程
  2. Android之利用ColorMatrix进行图片的各种特效处理
  3. Spring事务的那些坑,这里都给你总结好了!
  4. 【数据结构与算法】之深入解析“合并两个有序数组”的求解思路与算法示例
  5. Android之获取证书文件(pfx格式)的公钥和私钥
  6. android照片备份软件下载,照片备份云相册app下载-照片备份云相册下载V1.9安卓版-西西软件下载...
  7. Linux系统【一】CPU+MMU+fork函数创建进程
  8. 遍历删除_面试难题:List 如何一边遍历,一边删除?
  9. 公司java框架让程序员变笨_框架会使程序员变笨吗?
  10. BZOJ3642 : [CEOI 2014] Cake
  11. Java -- IO
  12. 【POJ2453】An Easy Problem
  13. 卫星通信 | 使用虹科SAF手持式频谱分析仪进行TDD信号分析
  14. 一体广告机实现思路,非常实用(一)
  15. python单核运行_python下多核,单核CPU对于并行,并发执行效率的对比-Go语言中文社区...
  16. “使用达芬奇软件实现Autosar架构:配置和注意事项“
  17. r1音箱原生系统更改服务器,低门槛不破坏R1功能改AUX音源电脑喇叭[已更新完整]...
  18. 如何让你画里的鱼,游进海里?
  19. 操作系统学习(第一章————第二章)
  20. nz-zero Icon图标的基本使用

热门文章

  1. Auto.js Pro安卓免ROOT引流脚本开发系列教程27网易公开课(5)-UI界面构建
  2. 服务器使用固态硬盘的优缺点
  3. cobbler部署与示例
  4. 在用户计算机上的万维网客户程序是( ),在用户计算机上的万维网客户程序是()...
  5. TOM 163VIP邮箱怎么登录?163.net邮箱登录界面是什么?
  6. CentOS系统磁盘的分区格式化和挂载操作
  7. 4G工业路由器的透传好处与安全因素
  8. English trip V2 - 8 Holidays and Birthdays Teacher:Julia Key: at on in
  9. 【tkinter】用不到50行Python代码,写一个扫雷小游戏
  10. 《软技能》读书笔记——职业篇