GeoHash原理解析
GeoHash 核心原理解析
引子

一提到索引,大家脑子里马上浮现出B树索引,因为大量的数据库(如MySQL、oracle、PostgreSQL等)都在使用B树。B树索引本质上是对索引字段进行排序,然后通过类似二分查找的方法进行快速查找,即它要求索引的字段是可排序的,一般而言,可排序的是一维字段,比如时间、年龄、薪水等等。但是对于空间上的一个点(二维,包括经度和纬度),如何排序呢?又如何索引呢?解决的方法很多,下文介绍一种方法来解决这一问题。
思想:如果能通过某种方法将二维的点数据转换成一维的数据,那样不就可以继续使用B树索引了嘛。那这种方法真的存在嘛,答案是肯定的。目前很火的GeoHash算法就是运用了上述思想,下面我们就开始GeoHash之旅吧。
一、感性认识GeoHash
首先来点感性认识,http://openlocation.org/geohash/geohash-js/ 提供了在地图上显示geohash编码的功能。
1)GeoHash将二维的经纬度转换成字符串,比如下图展示了北京9个区域的GeoHash字符串,分别是WX4ER,WX4G2、WX4G3等等,每一个字符串代表了某一矩形区域。也就是说,这个矩形区域内所有的点(经纬度坐标)都共享相同的GeoHash字符串,这样既可以保护隐私(只表示大概区域位置而不是具体的点),又比较容易做缓存, 比如左上角这个区域内的用户不断发送位置信息请求餐馆数据,由于这些用户的GeoHash字符串都是WX4ER,所以可以把WX4ER当作key,把该区 域的餐馆信息当作value来进行缓存,而如果不使用GeoHash的话,由于区域内的用户传来的经纬度是各不相同的,很难做缓存。

2)字符串越长,表示的范围越精确。如图所示,5位的编码能表示10平方千米范围的矩形区域,而6位编码能表示更精细的区域(约0.34平方千米)

3)字符串相似的表示距离相近(特殊情况后文阐述),这样可以利用字符串的前缀匹配来查询附近的POI信息。如下两个图所示,一个在城区,一个在郊区,城区的GeoHash字符串之间比较相似,郊区的字符串之间也比较相似,而城区和郊区的GeoHash字符串相似程度要低些。
|
|
|
通 过上面的介绍我们知道了GeoHash就是一种将经纬度转换成字符串的方法,并且使得在大部分情况下,字符串前缀匹配越多的距离越近,回到我们的案例,根 据所在位置查询来查询附近餐馆时,只需要将所在位置经纬度转换成GeoHash字符串,并与各个餐馆的GeoHash字符串进行前缀匹配,匹配越多的距离 越近。
二、GeoHash算法
一 个Geohash使用“之字形”的路线扫描一个2维的空间,而且遍历中的移动可以被简单地用0和1来表示其方向,然后在移动的过程中产生0/1串。下图展 示了这一算法:(陈皓注:先把地图分成四份,经度为第一位,纬度为第二位,于是左边的经度是0,右边的是1,纬度也一样,上面是为1,下面的为0,这样, 经纬度就可以组合成01,11,00,10这四个值,其标识了四块区域,我们可以如此不断的递归地对每个区域进行四分,然后可以得到一串1和0组成的字 串,然后使用0-9,b-z 去掉(去掉a, i, l, o)这32个字母进行base32编码得到一个8个长度的编码,这就是Geohash的算法)
Geohash的最强大的功能是使用简单的位操作就可以知道两个区域间的距离,就像图中所示(陈皓:proximity框着的那两个,这个很像IP地址了)。Geohash把一个二维的坐标生生地变成了一个一维的数据模型,这就是降维技术。

Geohash Index
这种类型的空间填充曲线的优点是将二维空间转换成一维曲线(事实上是分形维),对大部分而言,编码相似的距离也相近, 但Peano空间填充曲线最大的缺点就是突变性,有些编码相邻但距离却相差很远,比如0111与1000,编码是相邻的,但距离相差很大。

除Peano空间填充曲线外,还有很多空间填充曲线,如图所示,其中效果公认较好是Hilbert空间填充曲线,相较于Peano曲线而言,Hilbert曲线没有较大的突变。为什么GeoHash不选择Hilbert空间填充曲线呢?可能是Peano曲线思路以及计算上比较简单吧,事实上,Peano曲线就是一种四叉树线性编码方式。

三、GeoHash Base32编码长度与精度
可以看出,当geohash base32编码长度为8时,精度在19米左右,而当编码长度为9时,精度在2米左右,编码长度需要根据数据情况进行选择。
摘自维基百科:http://en.wikipedia.org/wiki/Geohash
四、使用注意点
1)
由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位置,绿色的
两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而较近餐馆的
GeoHash编码与我们不一致。这个问题往往产生在边界处。

解决的思路很简单,我们查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,这样可以避免这个问题。
2)我们已经知道现有的GeoHash算法使用的是Peano空间填充曲线,这种曲线会产生突变,造成了编码虽然相似但距离可能相差很大的问题,因此在查询附近餐馆时候,首先筛选GeoHash编码相似的POI点,然后进行实际距离计算。
参考文献:
http://en.wikipedia.org/wiki/Geohash
http://openlocation.org/geohash/geohash-js/
Cantor空間填充曲線之演算法探討.pdf
geohash:用字符串实现附近地点搜索 http://tech.idv2.com/2011/07/05/geohash-intro/
GeoHash核心原理解析 http://www.cnblogs.com/LBSer/p/3310455.html
NoSQL 数据建模技术 http://coolshell.cn/articles/7270.html
GeoHash原理解析的更多相关文章
- 【算法】(查找你附近的人) GeoHash核心原理解析及代码实现
本文地址 原文地址 分享提纲: 0. 引子 1. 感性认识GeoHash 2. GeoHash算法的步骤 3. GeoHash Base32编码长度与精度 4. GeoHash算法 5. 使用注意点( ...
- [原][Docker]特性与原理解析
Docker特性与原理解析 文章假设你已经熟悉了Docker的基本命令和基本知识 首先看看Docker提供了哪些特性: 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上, ...
- Web APi之过滤器执行过程原理解析【二】(十一)
前言 上一节我们详细讲解了过滤器的创建过程以及粗略的介绍了五种过滤器,用此五种过滤器对实现对执行Action方法各个时期的拦截非常重要.这一节我们简单将讲述在Action方法上.控制器上.全局上以及授 ...
- Web APi之过滤器创建过程原理解析【一】(十)
前言 Web API的简单流程就是从请求到执行到Action并最终作出响应,但是在这个过程有一把[筛子],那就是过滤器Filter,在从请求到Action这整个流程中使用Filter来进行相应的处理从 ...
- alibaba-dexposed 原理解析
alibaba-dexposed 原理解析 使用参考地址: http://blog.csdn.net/qxs965266509/article/details/49821413 原理参考地址: htt ...
- 支付宝Andfix 原理解析
支付宝Andfix 原理解析 使用参考地址: http://blog.csdn.net/qxs965266509/article/details/49802429 原理参考地址: http://blo ...
- JavaScript 模板引擎实现原理解析
1.入门实例 首先我们来看一个简单模板: <script type="template" id="template"> <h2> < ...
- Request 接收参数乱码原理解析三:实例分析
通过前面两篇<Request 接收参数乱码原理解析一:服务器端解码原理>和<Request 接收参数乱码原理解析二:浏览器端编码原理>,了解了服务器和浏览器编码解码的原理,接下 ...
- Request 接收参数乱码原理解析二:浏览器端编码原理
上一篇<Request 接收参数乱码原理解析一:服务器端解码原理>,分析了服务器端解码的过程,那么浏览器是根据什么编码的呢? 1. 浏览器解码 浏览器根据服务器页面响应Header中的“C ...
随机推荐
- jenkins+git+maven搭建自动化部署项目环境
简介 折腾了两个晚上,趁着今晚比较有空,把jenkins+git+maven搭建自动化部署项目环境搭建的过程记录一下,这里我把github作为git的远程仓库(https://github.co ...
- Centos7下配置Redis开机自启动
最近在做作业的时候需要用到Redis缓存,由于每次重启服务器都需要重新启动Redis,也是忒烦人,于是就有了这一篇博客,好,废话不多说. 只有两个步骤: 设置redis.conf中daemonize为 ...
- svn设置外网访问
1.设置路由器 默认协议为:https 端口号:443 服务器地址:https://主机名/svn/版本库 例:https://mleo-pc/svn/Share/ 也可就主机名用IP地址代替 如:h ...
- java根据标点英文分词
最近学习java字符串部分,用正则表达式做了一个简单的统计单词出现次数的小程序,目前只能统计英文. 整个程序包括三个包,分别为output,run,wordcount wordCount包 执行单词统 ...
- Linux内核原子(1) - spinlock的实现
spinlock的数据结构spinlock_t定义在头文件linux/spinlock_types.h里面: typedef struct { raw_spinlock_t raw_lock; #if ...
- 20169212《Linux内核原理与分析》第四周作业
Linux第四周作业 1. 堆栈知识 首先回顾了下堆栈相关的知识,堆栈机制是高级语言可以运行的一个基础,这一块需要重点掌握.函数发生调用时,如图 call指令:将eip的按顺序执行的下一条指令(因为在 ...
- input框只能输入整数和浮点数非数字就不输入
<input type="text" onInput="clearNoNum(this)" > //需引入jquery <script> ...
- Linux系统Vsftp 传文件出现 553 Could Not Create File错误的解决方法
解决方法: 登录出现了这个错误提示:553 Could not create file SELinux设置如下 查看SELinux设置 [root@localhost ~]# getsebool -a ...
- 2015年最好的PHP框架调查统计
2015年最流行的框架,Laravel框架获得赢家! 正如预期的那样,Laravel这次又一次高出了一大截. 有一些人可能会担心,部分框架分裂版本可能影响Laravel的调查结果,并给它一个不公平的优 ...
- session_id 恢复 session的内容
php的session是可以程序恢复的,这个和java不太一样.session的恢复机制可以实现多个应用程序session的共享,因为php的session都是以文件形式或者数据库存储的.首先是ses ...

