华建河北住房和城乡建设厅网站,天津专业做网站,广东省住房和城乡建设厅网站 粤建网,郑州seo实战培训目录
前言
一、GeoHash 的编码方法
二、Redis 操作GEO类型 前言
我们有一个需求是用户搜索附近的店铺#xff0c;就是所谓的位置信息服务#xff08;Location-Based Service#xff0c;LBS#xff09;的应用。这样的相关服务我们每天都在接触#xff0c;用滴滴打车就是所谓的位置信息服务Location-Based ServiceLBS的应用。这样的相关服务我们每天都在接触用滴滴打车中午去美团订外卖等等。当我们用这些服务方便我们的生活的时候大家有没有想过是怎么实现的。目前市场上很多软件比如EsRedis 都提供了类似的功能他们底层都是用的GeoHash 编码只不过底层的数据结构不同。今天主要讲的是Redis 的 Geo 如何实现这个功能
一、GeoHash 的编码方法
Redis 常用的数据类型有String字符串、List列表、Hash哈希、Set集合和 Sorted Set有序集合。位置信息存储一定是keyvaluevalue 就是经纬度。用List、HashSet 去存储没有办法去排序当然也是不可以的。最接近的数据结构是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]12[0,90)[90,180][90,180]13[90,135)[135,180][90,135)04[90,112.5)[112.5,135][112.5,135]15[112.5,123.75)[123.75,135][112.5,123.75)0
最终编码是11010
纬度的编码过程是 39.86
分区次数左分区右分区纬度 39.86所在的分区编码1【-900【0,90]【0,90]12[0,45)[45,90][45,90]03[0,22.5)[22.5,45][22.5,45]14[22.5,33.75)[33.75,45][33.75,45]15[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 官网提供了非常宝贵的资料