轨迹挖掘(四)--基于geohash的临近搜索

引言

在地理信息中,我们经常要做一个范围搜索,这个往往也是性能的瓶颈,今天我们就来介绍基于geohash的临近搜索。

geohash

首先我们来介绍什么是geohash,geohash简单来说是一种地理编码,就是你给我输入一个经纬度,我给你一个字符串编码。

我们可以简单思考一下,如果让你做范围搜索,你怎么来做索引呢?如果用树的思路,一定是不断的切分现有的空间域,从而加快搜索速度,geohash也是同样的道理。基于的实事就是我们的纬度的范围是(-90,90),同理经度也是指定范围内的数字而已,所以我们基于这个固定的范围不断做切分就好了。下面我们来看看过程

编码过程

我们来编码点(39.923201, 116.390705)

经度范围划分区域(1)划分区域(0)39.923201
(-90,90)(-90,0)(0,90)1
(0,90)(0,45)(45,90)0
............

最后得到纬度的二进制表示为:

 10111000110001111001

经度的编码

 11010010110001000100

然后让我们将经纬度合并,经度占偶数位,纬度占奇数位,注意,0也是偶数位。

11100 11101 00100 01111 00000 01101 01011 00001

按照Base32进行编码

 wx4g0ec1

这样我们将一个经纬度表达,变成一个字符串表达啦,这个时候你可以还是有疑问,这个和范围搜索有啥问题。

可以设想一下,我们将地图上所有的地标经纬度,全部编码成指定位数的geohash,那么使用geohash我们是不是就能很快找到,这个分块内的地标呢?

geohash的位数

从上面的geohash的计算过程,我知道,其实我们能把这个geohash编码成任意精度,那么这个位数和精度的关系是是什么呢?
image.png

这个图有比较好的说明效果,假如我们编码geohash8位,其实我们是能搜索附近19m的对象。

geohash的缺点

你可能已经感受到了,geohash是一个固定的编码,也就是这个编码是一个矩形,我如果编码8位geohash,其实我是搜索我所在的矩形的附近19m的对象,并不是真正的19m对象。对的,这个也是geohash的缺点,边界bad case频发,那么如何来解决这个问题呢?

其实我们一般是通过目标节点的geohash,获取周边8个块内的对象一起搜索。
image.png

这张图就是我们说的搜索范围,怎样保证你搜索的对象都不会少。

项目落地

说了这么多这个geohash在业务中我们怎么使用呢?

场景1

微信的附近的人是一个比较好场景,我们可以根据精度搜索周边上线的用户,开始聊天。

MM匹配

本博客上篇文章讲到MM(map match)算法,有一个过程就是我们要搜索目标点周边的link数据,这个就是很好的geohash的场景。

python使用

python中我们一般使用python-geohash的第三方包来解决geohash的算法。

import geohash
code = geohash.encode(longitude=116.390705,latitude=39.923201, precision=8)

neighbors = geohash.expand(code) # 获取包括自己周边9个块

总结

geohash在工程是比较常用的基于范围的索引方式,实际应用我们可以把点编码好放到redis中,从而搜索也十分高效。从另一个角度来讲,geohash也是一个典型的二分思想,类似于构建一个树,然后在树上搜索。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×