当前位置: 首页 > news >正文

Redis核心技术与实战【学习笔记】 - 7.Redis GEO类型 - 面向 LBS 应用的数据类型

前言

前面,介绍了 Redis 的 5 大基本数据类型:String、List、Hash、Set、Sorted Set,它们可以满足绝大多数的数据存储需求,但是在面对海里数据统计时,它们的内存开销很大。所以对于一些特殊的场景,它们是无法支持的。所以,Redis 还提供了 3 种扩展数据类型,分别是 Bitmap、HyperLogLog、GEO。今天再介绍下 GEO。


1.面向 LBS 应用的 GEO 数据类型

日常生活中,“附近停车场”、打车软件的叫车,这些都离不开基于位置信息服务(LBS)的应用。LBS 应用访问的数据是和人或物关联的一组经纬度信息,且要能查询相邻的经纬度范围,Redis 的 GEO 就非常适合应用在 LBS 服务的场景中。

1.1 GEO 底层结构

在设计一个数据类型的底层结构时,首先要知道,要处理的数据有什么访问特点。所以,需要先搞清楚位置信息到底是怎么存取的。

以叫车服务为例,来分析下 LBS 应用中经纬度的存取特点:

  1. 每辆网约车都有一个编号(如 1001),网约车需要将自己的经纬度信息(如 117.273521 , 39.884737)发给叫车应用。
  2. 用户在叫车的时候,叫车应用会根据用户的经纬度信息( 117.273521 , 39.884740)查找用户附件的车辆,并进行匹配。
  3. 等把位置相近的用户和车辆匹配上以后,叫车应用就会根据车辆的编号,获取车辆的信息,并返回给用户。

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

这种数据属于一个 key (例如车辆 ID) 对应一个 value(一组经纬度)。当有很多车辆信息需要保存时,就需要有一个集合来保存一系列的 key 和 value。Hash 集合类型可以快速存取一系列 key 和 value,正好可以记录一系列车辆 ID 和经纬度的对应关系,如下所示:
在这里插入图片描述
此外,Hash 类型的 HSET 操作,可以快速的更新车辆变化的经纬度信息。

目前看来,Hash 类型是一个不错的选择。但是,一个 LBS 应用除了记录经纬度信息外,还需要根据用户经纬度信息在车辆的 Hash 集合中进行范围查找。一旦涉及到范围查询,就意味着集合中的数据是有序的,但 Hash 类型是无需的,不能满足要求。

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

而 GEO 类型的底层数据结构就是用 Sorted Set 来实现的。咱们还是接着叫车应用例子,用 Sorted Set 来保存车辆的经纬度信息时,Sorted Set 的元素是车辆 ID,元素的权重分数是经纬度信息,如下图所示:
在这里插入图片描述
此时问题是,Sorted Set 元素的权重分数是一个浮点数(float 类型),而一组经纬度包含的精度和纬度两个值,是没法直接保存为一个浮点数。这就要用到 GEO 类型中的 GeoHash 编码了。

1.2 GeoHash 编码方法

Redis 采用了 GeoHash 编码方法,这个方法的基本原理就是“二分区间,区间编码”。当我们要对一组经纬度进行 GeoHash 编码时,要先对经度和纬度分别编码,然后把经纬度各自的编码组合成一个最终编码。

首先,看下经度和纬度的单独编码过程。

  1. 对于一个地理位置来说,经度范围是 [-180, 180]。
  2. GeoHash 编码会把一个经度值编码成一个 N 位的二进制值,我们来对经度范围 [-180, 180] 做 N 次的二分区操作,其中 N 可以自定义。
  3. 在进行第一次区分时,经度范围 [-180, 180] 会被分成两个子区间:[-180, 0) 和 [0, 180]。此时,看一下编码的经度值是落在了左分区还是右分区。 如果是落在做分区,我们就用 0 表示;如果落在右分区,就用 1 表示。这样一来,每做完一次二分区,我们就可以得到 1 位编码值。
  4. 再对经度值所属的分区,再做一次二分区,同时再次查看经度落在了新二分区的做分区还是右分区,按照刚才的规则再做 1 位编码。当做完 N次的二分区后,经度值就可以用一个 N bit 的数来表示了。

举个例子,假设我们要编码的经度值是 117.273521 ,我们用 5 位编码值(也就是 N = 5,做 5 次分区)。
5. 先做第一次二分区操作,把经度区间 [-180, 180] 分成两个子区间:[-180, 0) 和 [0, 180],此时,经度值 117.273521 是属于右分区 [0, 180],所以,我们用 1 表示第一次二分区后的编码值。
6. 再做第二次二分区:把经度值 117.273521 所属分区 [0, 180] 区间,分成 [0, 90) 和 [90, 180]。此时经度值 117.273521 还是属于右分区 [90, 180],编码值仍为 1。
7. 第三次二分区,经度值 117.273521 落在了左分区 [90, 135) 中,所以,第三次分区后的编码值就是 0。
8. 第四次二分区,经度值 117.273521 落在了右分区 [112.5, 135]中,所以第四次编码值就是 1。
9. 第五次二分区,经度值 117.273521 落在了左分区 [112.5, 123.75) 中,所以第五次次编码值就是 0。

最终,做完 5 次分区后,我们把经度值 117.273521 的 GeoHash 编码值为 11010

对维度的编码方式,和对经度一样,只是经度的范围是 [-90, 90],GeoHash 编码的值为 10111,下标展示了对纬度值 39.884737 的编码过程。

分区次数最小维度值二分区中间值最大维度值维度39.884737所在区间维度的GeoHash编码
第一次-90090[0, 90]1
第二次04590[0, 45)0
第三次022.545[22.5, 45]1
第四次22.533.7545[33.75, 45]1
第五次33.7539.37545[39.375, 45)1

我们再把一组经纬度值都编完码后,再把它们组合在一起,组合的规则是:

  • 最终编码值的偶数位上依次是经度的编码值
  • 奇数位上依次是纬度的编码值
  • 其中偶数位从 0 开始,奇数位从 1 开始。

我们把刚刚计算的经纬度(117.273521, 39.884737)的各自编码值 11010 和 10111 ,组合之后:

  • 第 0 位 :经度的第 0 位 ,为 1
  • 第 1 位:纬度度的第 0 位,为 1
  • 第 2 位:经度的第 1 位,为 1
  • 依次类推,就能得到最终的编码值: 1 1 1 0 0 1 1 1 0 1(加粗的为经度编码值,其他是纬度编码值)

用了 GeoHash 编码后,原本无法表示权重的经纬度,就可以用 1110011101 这个值来表示,就可以保存为 Sorted Set 的权重分数了。

其实,使用 GeoHash 编码后,就相当于把整个地理空间划分成一个个放个,每个放个对应了一个 GeoHash 中的一个分区。举个例子。 我们把经度区间 [-180,180] 做一次二分区,把维度区间 [-90,90] 做一次二分区间,就会得到 4 个分区。我们看看经度和纬度范围及对应的 GeoHash 组合编码:

  • 分区一:[-180, 0) 和 [-90, 0),编码 00
  • 分区二:[-180, 0) 和 [0, 90),编码 01
  • 分区三:[0, 180) 和 [-90, 0),编码 10
  • 分区三:[0, 180) 和 [0, 90),编码 11

这 4 个分区对应了 4 个方格,每个方格覆盖了一定范围内的经纬度,分区越多,每个方格能覆盖到的地理位置就越小,也就越精准。我们把所有方格的编码值映射到一维空间内,相邻方格的 GeoHash 编码值基本也是接近的,如下所示:
在这里插入图片描述
所以,我们使用 Sorted Set 范围查询得到的相近编码值,在实际的地理空间上,也是相邻的方格,这就可以实现 LBS 应用搜索附件人或物的功能了。

不过,需要注意的是,有的编码值虽然在大小上接近,但实际对应的方格确距离比较远。例如,我们用 4 魏来做 GeoHash 编码,把经度区间 [-180,180] 和纬度区间 [-90,90] 分成了 4 个分区,一共 16 个分区。编码值为 0111 和 1000 的两个方格就离的比较远,如下所示:
在这里插入图片描述
所以,为了避免查询不准确问题,我们可以同时查询给定经纬度所在的方格周围的 4 个或 8 个方格。

好了,现在我们知道 GEO 类型是把经纬度所在区间编码作为 Sorted Set 中元素的权重分数,把和经纬度相关的车辆 ID 作为 Sorted Set 中元素本身的值保存下来,这样相邻经纬度的查询就可以通过编码值的大小范围来实现了。

1.3 如何操作 GEO 类型

在使用 GEO 类型的时,我们经常会用到两个命令,分别是 GETADD 和 GEORADIUS。

  • GETADD:把一组经纬度和相对应的一个 ID 记录到 GEO 类型集合中;
  • GEORADIUS:会根据输入的经纬度未知,查找这个纬度为中心的一定范围内的其他元素。

假设车辆 ID 是 1001,经纬度位置是 (117.273521, 39.884737),我们可以用一个 GEO 集合保存所有车辆的经纬度,集合 key 是 cars:locations。执行下面的这个命令,就可以把 ID 号为 1001 的车辆的当前经纬度位置存入 GEO 集合中:

GEOADD cars:locations 117.273521 39.884737 1001

当用户想要查看自己附近的网约车是,LBS 应用就可以使用 GEORADIUS 命令。例如,LBS 应用执行下面的命令时,Redis 会根据输入的用户的经纬度信息( 117.273521 , 39.884740),查找这个经纬度为中心的 5 公里内的车辆信息,并返回给 LBS 应用。

GEORADIUS cars:locations 117.273521 39.884740 5 km ASC COUNT 10

当然,你可以修改 “5” 这个参数,来返回更大或更小范围内的车辆信息。此外,还可以进一步限定返回的车辆信息。

  • 比如我们可以使用 ASC 选项,让返回的车辆按照距离这个中心位置从近到源的方式来排序,以边防选择最近的车辆;
  • 还可以使用 COUNT 选项,指定返回的车辆信息的数量。毕竟,5 公里内的车辆可能有很多,如果返回全部信息,会占用比较多的数据带宽,这个选项可以帮助控制返回的数据量,节省带宽。

可以看到,使用 GEO 数据类型可以非常轻松地操作经纬度这种信息。

相关文章:

Redis核心技术与实战【学习笔记】 - 7.Redis GEO类型 - 面向 LBS 应用的数据类型

前言 前面,介绍了 Redis 的 5 大基本数据类型:String、List、Hash、Set、Sorted Set,它们可以满足绝大多数的数据存储需求,但是在面对海里数据统计时,它们的内存开销很大。所以对于一些特殊的场景,它们是无…...

银行数据仓库体系实践(17)--数据应用之营销分析

营销是每个银行业务部门重要的工作任务,银行产品市场竞争激烈,没有好的营销体系是不可能有立足之地,特别是随着互联网金融发展,金融脱媒”已越来越普遍,数字化营销方兴未艾,银行的营销体系近些年也不断发展&#xff0c…...

Linux一键部署telegraf 实现Grafana Linux 图形展示

influxd2前言 influxd2 是 InfluxDB 2.x 版本的后台进程,是一个开源的时序数据库平台,用于存储、查询和可视化时间序列数据。它提供了一个强大的查询语言和 API,可以快速而轻松地处理大量的高性能时序数据。 telegraf 是一个开源的代理程序,它可以收集、处理和传输各种不…...

C/C++ C++入门

个人主页:仍有未知等待探索-CSDN博客 专题分栏:C_仍有未知等待探索的博客-CSDN博客 目录 一、C关键字 二、命名空间 1、区别 1. C语言 ​编辑 2. C 2、命名空间定义 3、命名空间的使用 三、C输入&输出 四、缺省参数 五、函数重载 六、引用 …...

【后端】乐观锁和悲观锁

前置知识点 锁:一种确保数据安全的机制和手段。 在多个线程修改共享变量时,我们可以对修改操作进行加锁。当多个用户修改表中的同一数据时,我们可以对该行数据进行加锁(行锁)。锁是用于控制多个操作在并发环境下按顺…...

软件工程知识梳理1-可行性研究

目的:确定问题是否值得去解决。就是用最小的代价在尽可能短的时间内确定问题是否能够解决。 可行性研究实质上是要进行一次大大压缩简化了的系统分析和设计的过程,也即是在较高层次上以较抽象的方式进行系统分析和设计的过程。 考察点:技术可…...

2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码

2024美国大学生数学建模E题财产保险的可持续模型详解思路具体代码 前言 很快啊!啪的一下拿到题目就开始做题!简单介绍一下我自己:博主专注建模五年,参与过大大小小数十来次数学建模,理解各类模型原理以及每种模型的建…...

pytorch nearest upsample整数型tensor

在用 torch.nn.Upsample 给分割 label 上采样时报错:RuntimeError: "upsample_nearest2d_out_frame" not implemented for Long。 参考 [1-3],用 [3] 给出的实现。稍微扩展一下,支持 h、w 用不同的 scale factor,并测试…...

MySQL的SQL MODE

目录 举例: --常见SQL mode --mysql8 sql_mode 官方文档 https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html --查看全局的SQL MODE select global.sql_mode; --查看当前会话的SQL MODE select session.sql_mode; --运行时修改全局的SQL mode set gl…...

GO EASY 框架 之 NET 05

目录 1、Overview 2、Agent接口源码 3、收发消息 4、AgentHandle接收函数 5、conns.Conn接口 1、Overview 名称:agent.Agent 网络链接 接口; DESC:网络链接,服务端与客户端通信媒介; 封装:进一步封…...

【教程】谈一谈 IPA 上传到 App Store Connect 的几种方法

【教程】谈一谈 IPA 上传到 App Store Connect 的几种方法 引言 在应用开发过程中,将应用程序上传到 App Store Connect 是一个关键的环节。本文将探讨几种常见的 IPA 文件上传方法,包括 Xcode、Application Loader、altool、Appuploader以及Transport…...

面试经典 150 题 -- 滑动窗口 (总结)

面试经典150题链接 面试经典 150 题 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台 209 . 长度最小的子数组 思路 : 滑动窗口的思想,取ij0,向后遍历j,记录前缀和[l,r]为s,如果s>target,那么左端点向右移动,直到s…...

JDK8对List对象根据属性排序

文章目录 JDK8对List对象根据属性排序1. 被排序字段为null或者空时候报错2. 使用Stream流排序2.1 根据name升序2.2 根据name升序,score降序 3. 使用Collections排序3.1 根据name升序3.2 根据name升序,score降序 4. 完整的demo JDK8对List对象根据属性排序…...

【2024美国大学生数学建模竞赛】2024美赛C题网球运动中的势头,网球教练4.0没人比我更懂这个题了!!!

【2023美国大学生数学建模竞赛】2024美赛C题 问题分析、数学模型、实现代码、完整论文 引言 本人是计算机博士,拥有10年网球球龄,2023年的温网决赛,熬夜到半夜全称观看完了直播,对于网球规则、比赛的数据非常熟悉,这个…...

python的Flask生产环境部署说明照做成功

最近刚好在我的Linux服务器上部署一个Web服务, 使用了python的Flask框架, 因此本文主要介绍flask在linux环境上的部署。 Flask 是一个轻量级的 Python Web 框架,非常适合快速开发小型到中型的 Web 应用。然而,Flask 自带的服务器通常是用于开发目的&…...

EXCEL VBA调用百度api识别身份证

EXCEL VBA调用百度api识别身份证 Sub BC_识别身份证()Dim SHD, SHX As WorksheetDim AppKey, SecretKey, Token, PathY As StringDim jSon, JSonA, WithHttp As ObjectDim Pic, oDom, oW, jsCode, paramsDim ARX, BRX, DRX, ERX, ZADDim StrText, StrUrl As StringDim StrA, S…...

【每日一题】7.LeetCode——合并两个有序链表

📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》|《数据结构与算法》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏小杨水平有限,欢…...

【零基础学习CAPL】——CAN报文的发送(按下按钮同时周期性发送)

🙋‍♂️【零基础学习CAPL】系列💁‍♂️点击跳转 文章目录 1.概述2.面板创建3.系统变量创建4.CAPL实现4.1.函数展示4.2.全量报文展示5.效果1.概述 本章主要介绍使用CAPL和Panel在按下按钮时发送周期性CAN报文。 本章主要在“【零基础学习CAPL】——CAN报文的发送(配合P…...

六、Nacos源码系列:Nacos健康检查

目录 一、简介 二、健康检查流程 2.1、健康检查 2.2、客户端释放连接事件 2.3、客户端断开连接事件 2.4、小结 2.5、总结图 三、服务剔除 一、简介 Nacos作为注册中心不止提供了服务注册和服务发现的功能,还提供了服务可用性检测的功能,在Nacos…...

2024美赛C题思路/代码:网球中的动量

美赛直播b站,提前关注:川川菜鸟 美赛辅导预定:美赛服务 去年美赛C题:2023美赛C题 题目翻译 背景 在2023年温布尔登男子单打决赛中,20岁的西班牙新星阿尔卡拉兹击败了36岁的诺瓦克德约科维奇。这是德约科维奇自201…...

ConcurrentHashMap原理详解(太细了)

一、什么是ConcurrentHashMap ConcurrentHashMap和HashMap一样,是一个存放键值对的容器。使用hash算法来获取值的地址,因此时间复杂度是O(1)。查询非常快。 同时,ConcurrentHashMap是线程安全的HashMap。专门用于多线程环境。 二、Concurre…...

EasyExcel根据对应的实体类模板完成多个sheet的写入与读取

1.展示模板一的实体类 import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowH…...

在企业数字化转型过程中,IT运维发挥着怎样的价值?

IT运维软件在企业数字化转型中发挥着重要的价值。从效率、稳定性、安全性和资源利用率以及数据分析决策支持都有巨大的提升。 提高效率 利用自动化巡检功能,实时或定时进行系统巡检,减少人力巡检的繁琐和低效,避免手动操作的失误&#xff0c…...

01-工厂模式 ( Factory Pattern )

工厂模式 Factory Pattern 摘要实现范例 工厂模式(Factory Pattern)提供了一种创建对象的最佳方式 工厂模式在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象 工厂模式属于创建型模式 摘要 1. 意图 …...

【LeetCode】每日一题 2024_2_2 石子游戏 VI(排序、贪心)

文章目录 LeetCode?启动!!!题目:石子游戏 VI题目描述代码与解题思路 LeetCode?启动!!! 题目:石子游戏 VI 题目链接:1686. 石子游戏 VI 题目描述…...

一站式在线协作开源办公软件ONLYOFFICE,协作更安全更便捷

1、ONLYOFFICE是什么? ONLYOFFICE是一款功能强大的在线协作办公软件,可以创建编辑Word文档、Excel电子表格,PowerPoint(PPT)演示文稿、Forms表单等多种文件。ONLYOFFICE支持多个平台,无论使用的是 Windows、…...

Java进击框架:Spring-综合(十)

Java进击框架:Spring-综合(十) 前言Rest ClientsWebClientRestTemplateHTTP接口 JMS (Java消息服务)使用Spring JMS发送消息接收消息注释驱动的侦听器端点 JMXEmail任务执行和调度Spring TaskExecutor 抽象Spring TaskScheduler 抽象支持调度…...

2024年第九届信号与图像处理国际会议(ICSIP 2024)

2024第九届信号与图像处理国际会议(ICSIP 2024)将于2024年7月12-14日在中国南京召开。ICSIP每年召开一次,在过去的七年中吸引了1200多名与会者,是展示信号和图像处理领域最新进展的领先国际会议之一。本次将汇集来自亚太国家、北美…...

webassembly003 MINISIT mnist/convert-h5-to-ggml.py

数据结构 # Convert MNIS h5 transformer model to ggml format # # Load the (state_dict) saved model using PyTorch # Iterate over all variables and write them to a binary file. # # For each variable, write the following: # - Number of dimensions (int) # …...

fetch和axios的区别

概念不同 Fetch是一种新的获取资源的接口方式,可以直接使用Axios是一个基于XMLHttpRequest封装的工具包,需要引入才可以使用 传递数据的方式不同 Fetch则是需要放在body属性中,以字符串的方式进行传递Axios是放到data属性里,以对象…...