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

redis之GEO 模块

文章目录

  • 背景
  • GeoHash 算法
  • redis中的GeoHash 算法
  • 基本使用
    • 增加
    • 距离
    • 获取元素位置
    • 获取元素的 hash 值
    • 附近的元素
  • 注意事项
  • 原理

背景

如果我们有需求需要存储地理坐标,为了满足高性能的矩形区域算法,数据表需要在经纬度坐标加上双向复合索引 (x, y),这样可以最大优化查询性能。但是数据库查询性能毕竟有限,如果「附近的人」查询请求非常多,在高并发场合,这可能并不是一个很好的方案。

GeoHash 算法

业界比较通用的地理位置距离排序算法是 GeoHash 算法, Redis 也使用 GeoHash 算
法。 GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。当我们想要计算「附近的人时」,首先将目标位置映射到这条线上,然后在这个一维的线上获取附近的点就行了。

那这个映射算法具体是怎样的呢?它将整个地球看成一个二维平面,然后划分成了一系列正方形的方格,就好比围棋棋盘。所有的地图元素坐标都将放置于唯一的方格中。方格越小,坐标越精确。然后对这些方格进行整数编码,越是靠近的方格编码越是接近。通过这种方式可以还原出元素的坐标,整数越长,还原出来的坐标值的损失程度就越小。对于「附近的人」这个功能而言,损失的一点精确度可以忽略不计。

redis中的GeoHash 算法

GeoHash 算法会继续对这个整数做一次 base32 编码 (0-9,a-z 去掉 a,i,l,o 四个字母) 变成一个字符串。在 Redis 里面,经纬度使用 52 位的整数进行编码,放进了 zset 里面, zset的 value 是元素的 key, score 是 GeoHash 的 52 位整数值。 zset 的 score 虽然是浮点数,但是对于 52 位的整数值,它可以无损存储。

在使用 Redis 进行 Geo 查询时,我们要时刻想到它的内部结构实际上只是一个
zset(skiplist)。通过 zset 的 score 排序就可以得到坐标附近的其它元素 (实际情况要复杂一些,不过这样理解足够了),通过将 score 还原成坐标值就可以得到元素的原始坐标。

基本使用

增加

geoadd 指令携带集合名称以及多个经纬度名称三元组,注意这里可以加入多个三元组

如:geoadd company 116.48105 39.996794 A
geoadd company 118.48105 37.996794 B

距离

geodist 指令可以用来计算两个元素之间的距离,携带集合名称、 2 个名称和距离单位。

如:geodist company A B km

获取元素位置

geopos 指令可以获取集合中任意元素的经纬度坐标,可以一次获取多个。

如:geopos company A

获取的经纬度坐标和 geoadd 进去的坐标有轻微的误差,原因是 geohash 对
二维坐标进行的一维映射是有损的,通过映射再还原回来的值会出现较小的差别。对于「附近的人」这种功能来说,这点误差根本不是事。

获取元素的 hash 值

geohash 可以获取元素的经纬度编码字符串。

如:geohash company A

附近的元素

georadiusbymember 指令是最为关键的指令,它可以用来查询指定元素附近的其它元
素,它的参数非常复杂。

如:georadiusbymember company A 20 km count 3 asc

除了 georadiusbymember 指令根据元素查询附近的元素, Redis 还提供了根据坐标值来查询附近的元素,这个指令更加有用,它可以根据用户的定位来计算「附近的车」,「附近的餐馆」等。它的参数和 georadiusbymember 基本一致,除了将目标元素改成经纬度坐标值。

注意事项

在一个地图应用中,车的数据、餐馆的数据、人的数据可能会有百万千万条,如果使用Redis 的 Geo 数据结构,它们将全部放在一个 zset 集合中。在 Redis 的集群环境中,集合可能会从一个节点迁移到另一个节点,如果单个 key 的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key 对应的数据量不宜超过 1M,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行。

所以,这里建议 Geo 的数据使用单独的 Redis 实例部署,不使用集群环境。

如果数据量过亿甚至更大,就需要对 Geo 数据进行拆分,按国家拆分、按省拆分,按
市拆分,在人口特大城市甚至可以按区拆分。这样就可以显著降低单个 zset 集合的大小。

原理

geo内部是基于zset来实现的,并且只使用一个zset。所以使用时要注意他的存储量。


http://www.mrgr.cn/news/89955.html

相关文章:

  • TensorFlow域对抗训练DANN神经网络分析MNIST与Blobs数据集梯度反转层提升目标域适应能力可视化...
  • xcode常见设置
  • 2、k8s的cni网络插件和基本操作命令
  • Chakra UI 使用经验
  • 如何在RTACAR中配置IP多播(IP Multicast)
  • C#面试常考随笔12:游戏开发中常用的设计模式【C#面试题(中级篇)补充】
  • mysql8 从C++源码角度看sql生成抽象语法树
  • 2025年日祭
  • unity学习29:摄像机camera相关skybox 和 Render Texture测试效果
  • 【LeetCode 刷题】贪心算法(2)-进阶
  • 第 26 场 蓝桥入门赛
  • Java中的继承及相关概念
  • .NET Core 8 Blazor 和 Vue 3 技术构建网
  • 微信小程序案例2——天气微信小程序(学会绑定数据)
  • Vite+TS项目中配置路径别名
  • OC-Block
  • 构建Ubuntu unminimized的docker镜像
  • 【前端】打造自己的hexo博客_hexo一本通
  • 使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)上安装 Java 8
  • Vite 打包原理
  • 【11天从零基础入门flask】第 6 章:模板优化
  • 激活函数篇 03 —— ReLU、LeakyReLU、ELU
  • 程序员也可以这样赚钱
  • Vite 为什么快,是怎么打包的
  • sqli-lab靶场学习(五)——Less15-17(post方法盲注、修改密码)
  • 深度剖析 Redisson 分布式锁:原理、实现与应用实践