redis GEO 类型原理及命令详解

news2024/11/25 4:06:02

目录

前言

一、GeoHash 的编码方法

二、Redis 操作GEO类型


前言

我们有一个需求是用户搜索附近的店铺,就是所谓的位置信息服务(Location-Based Service,LBS)的应用。这样的相关服务我们每天都在接触,用滴滴打车,中午去美团订外卖等等。当我们用这些服务方便我们的生活的时候,大家有没有想过是怎么实现的。目前市场上很多软件比如Es,Redis 都提供了类似的功能,他们底层都是用的GeoHash 编码,只不过底层的数据结构不同。今天主要讲的是Redis 的 Geo 如何实现这个功能

一、GeoHash 的编码方法

Redis 常用的数据类型有String(字符串)、List(列表)、Hash(哈希)、Set(集合)和 Sorted Set(有序集合)。位置信息存储一定是key,value,value 就是经纬度。用List、Hash,Set 去存储,没有办法去排序,当然也是不可以的。最接近的数据结构是Sorted Set,可以根据score 排序同时也满足范围获取。又有一个问题是 score 是 float 类型的,经纬度不是的,好像也不可以,能不能用一种编码把经纬度变成float 类型的,这种编码就是GeoHash。

为了能高效地对经纬度进行比较,Redis 采用了业界广泛使用的 GeoHash 编码方法,这个方法的基本原理就是“二分区间,区间编码”。当我们用GeoHash编码时,我们要先对经度和维度分别编码,然后再把经纬度各自的编码组合成一个最终编码。

我们看看经纬度的编码过程。

对于一个定理信息来说,它的经度范围是[-180,180],纬度范围是[-90,90]。GeoHash编码会把经,纬度做N次二分区操作,其中N是自定义的。

先拿经度来说,范围是[-180,180]会被分成两个子区间:【-180,0)和【0,180】(我称为左右分区)。此时我们要看下经度是落在左右哪个分区上,落在左分区用0表示,又分区用1 表示。第二次在把落在的分区又分成左右两个分布,在看下经度是落在哪个分区上,落在左分区用0表示,又分区用1 表示。依次类推,只要分成了N份结束了。最终得到的是N bit 的位数,例如10111 这样的数据。

纬度也是同样的,只不过,纬度的范围是【-90,90】。每次也是平均分成左右两个分区,落在左分区用0表示,又分区用1 表示。最终得到的也是N bit 的位数,例如10110 这样的数据。

最终得倒的是2个N bit 的位数,最终进行组合。组合规则是第 0 位是经度的第 0 位 1,第 1 位是纬度的第 0 位 1,第 2 位是经度的第 1 位 1,第 3 位是纬度的第 1 位 0。

下面我们会举一个例子,来阐述算法具体的实现:经度值 116.37,纬度值 39.86, N是5。

经度分区过程 116.37:

分区次数左分区右分区经度116.37所在的分区编码
1【-180,0)[0,180][0,180]1
2[0,90)[90,180][90,180]1
3[90,135)[135,180][90,135)0
4[90,112.5)[112.5,135][112.5,135]1
5[112.5,123.75)[123.75,135][112.5,123.75)0

最终编码是11010

纬度的编码过程是 39.86

分区次数左分区右分区纬度 39.86所在的分区编码
1【-90,0)【0,90]【0,90]1
2[0,45)[45,90][45,90]0
3[0,22.5)[22.5,45][22.5,45]1
4[22.5,33.75)[33.75,45][33.75,45]1
5[33.75,39.375)[39.375.45][39.375,45]1

最终编码是 10111

GeoHash最终编码是,回顾编码规则:组合规则是第 0 位是经度的第 0 位 1,第 1 位是纬度的第 0 位 1,第 2 位是经度的第 1 位 1,第 3 位是纬度的第 1 位 0

经度编码11010
奇偶数(位数)0123456789
纬度编码10111

经度编码和纬度编码合并:一共是10位数, 1110011101,位数不要错了,这个最终就是 Sorted Set 的 sort 值了。

当然,使用 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 个分区,对应了 16 个方格。编码值为 0111 和 1000 的两个方格就离得比较远,如下图所示:

二、Redis 操作GEO类型

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

GEOADD 命令:用于把一组经纬度信息和相对应的一个 ID 记录到 GEO 类型集合中;

GEORADIUS 命令:会根据输入的经纬度位置,查找以这个经纬度为中心的一定范围内的其他元素。当然,我们可以自己定义这个范围。

操作如下:

GEOADD 如果member 没有就增加,有就是修改,用 GEOPOS cars:locations 33 可以看到每个member 具体的经纬度

GEORADIUS 可以根据坐标找到相应的member。命令的详解可以看官网文档 GEORADIUS | Redis

非常感谢 蒋德钧的《Redis 核心技术与实战》以及 redis 官网提供了非常宝贵的资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1465414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件夹无法压缩是怎么回事?分享3种简单的方法~

在日常使用电脑的过程中,我们经常需要对文件夹进行压缩,以节省存储空间或方便传输。然而,有时候我们可能会遇到文件夹无法压缩的情况,这可能会让人感到困惑。本文将探讨文件夹无法压缩的原因,并提供解决方法&#xff0…

谷粒商城-nginx搭建域名访问环境性能压测

nginx搭建域名访问环境 正向代理与反向代理 正向代理:客户端向代理服务器发请求并指定目标服务器,代理向目标服务器转交请求并将获得的内容返回给客户端。 反向代理:用户直接访问反向代理服务器就可以获得目标服务器的资源。反向代理服务器…

基于EasyCVR视频汇聚系统的公安网视频联网共享视频云平台建设思路分析(二)

一、需求分析 随着科技的飞速发展,视频监控联网技术在公安工作中发挥着越来越重要的作用。为了提高公安部门对各类事件的响应速度和处理能力,建设一个高效、稳定的公安视频联网共享云平台显得尤为重要。通过建设开放的视频联网共享云平台,实…

Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】

有的自定义系统,对于自己外接的USB摄像头,android原生的camera和camera2都无法打开,CameraX也用不了。这时候就要用libusbCamera,这个库可以打开摄像头,还可以多摄像头同时预览。本文主要是同时打开3个USB摄像头的项目…

C语言第二十九弹---浮点数在内存中的存储

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 目录 1、浮点数在内存中的存储 1.1、练习 1.2、浮点数怎么转化为二进制 1.3、浮点数的存储 1.3.1、浮点数存的过程 1.3.2、浮点数取的过程 1.3、题目解析…

配置开机自启

进入任务计划程序 点击创建基本任务,按照向导一步一步进行下去

【数据结构】排序(1)

目录 一、概念: 二、直接插入排序: 三、希尔排序: 四、直接选择排序: 五、堆排序: 六、冒泡排序: 一、概念: 排序的概念: 使一串记录,按照其中的某个或某些关键字…

阿里巴巴店铺宝藏全揭秘:一键获取所有商品信息,电商业务效率飙升

阿里巴巴店铺所有商品API接口技术全解析 一、引言 在阿里巴巴这个全球领先的电商平台上,店铺所有商品API接口(item_search_shop)为开发者提供了一个便捷的途径,能够获取店铺的所有商品信息。通过这一接口,无论是数据…

PostgreSQL教程(十一):SQL语言(四)之数据类型

一、数值类型 数值类型由 2 字节、4 字节或 8 字节的整数以及 4 字节或 8 字节的浮点数和可选精度的十进制数组成。 下表列出了所有可用类型。 数值类型 名字存储长度描述范围smallint2 字节小范围整数-32768 到 32767integer4 字节常用的整数-2147483648 到 2147483647bigi…

【无标题】旋转链表与力扣报错:member access within null pointer of type ‘struct ListNode‘

项目场景: 做单链表反转题目,报错:member access within null pointer of type ‘struct ListNode’ 题目链接:LINK 问题描述 我明明在初始化指针时候,已经处理了n2->next情况却依然报错 这个报错提示含义是:大概就…

HTTPS(超文本传输安全协议)被恶意请求该如何处理。

HTTPS(超文本传输安全协议)端口攻击通常是指SSL握手中的一些攻击方式,比如SSL握手协商过程中的暴力破解、中间人攻击和SSL剥离攻击等。 攻击原理 攻击者控制受害者发送大量请求,利用压缩算法的机制猜测请求中的关键信息&#xf…

每天一个知识点 - 如何快速熟悉后端项目

入职一家新公司的时候,不可避免的就是接触到新公司的项目,有些项目一启动就是好几年,业务功能极其复杂,下面我总结几个方法让大家快速熟悉后端项目(图文结合) 用例图简析 用例是系统中的一个功能单元&…

顶级性能更有AI助力 RTX AI轻薄本竟强大如斯?华硕无畏Pro15 2024体验

不知觉,2024龙年腾飞之年俨然到来。回望这过去的一年里,我们的生活发生了很多变化🏮 有对身体健康的焦虑,也有对事业发展的迷茫,也时常回过头来反思自己在过去的一年里都有哪些不足、希冀在新的一年里努力改进自己&am…

Windows环境下查看磁盘层级占用空间的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Unity之ShaderGraph如何实现水面波浪

前言 这几天通过一个水的波浪数学公式,实现了一个波浪效果,感觉成就感满满,下面给大家分享一下 首先先给大家看一下公式; 把公式转为ShaderGraph 第一行公式:waveType = z*-1*Mathf.Cos(wave.WaveAngle/360*2*Mathf.PI)+x*Mathf.Sin(WaveAngle/360*-2*Mathf.PI) 转换…

基于JAVA的公司货物订单管理系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 客户管理模块2.2 商品维护模块2.3 供应商管理模块2.4 订单管理模块 三、系统展示四、核心代码4.1 查询供应商信息4.2 新增商品信息4.3 查询客户信息4.4 新增订单信息4.5 添加跟进子订单 五、免责说明 一、摘要 1.1 项目…

端口占用:Web server failed to start. Port XXX was already in use.原因分析-解决方案

一、windows 1.Web server failed to start. Port XXX was already in use出错原因分析 端口被占用了,我们只需要换一个端口就可以了,如果就想要用特定的端口,我们需要使用下面的命令,先找到对应端口号的进程号,然后结…

【QT-lineEidte动画效果

QT-lineEidte动画效果 一、演示效果二、核心代码三、下载链接 一、演示效果 二、核心代码 #ifndef DynamicUnderlineLineEdit_H #define DynamicUnderlineLineEdit_H#include <QWidget> #include <QLineEdit> #include <QPainter> #include <QPaintEvent…

产品渲染3D效果图一张多少钱,哪个平台更有性价比?

产品渲染3D效果图的价格受到多方面因素的影响&#xff0c;包括但不限于产品类型、渲染难度以及输出尺寸等。如果效果图需要后期处理&#xff0c;还有可能增加其他费用。接下来&#xff0c;我们来了解一下产品渲染效果图的费用情况。 1.产品渲染3D效果图一张多少钱&#xff1f; …

最长的回文串

开始想的简单了&#xff0c;确实没想到奇数字母删去一个后也能用 解法&#xff1a; 桶排序 #include<iostream> #include<vector> #include<algorithm> using namespace std; #define endl \n #define int long long signed main() {int t;cin >> t…