我正在寻找优化点邻近地理搜索时间的方法。
我的输入是lat,lng点,我正在搜索到n个最近点的一组预先计算的位置。
我不在乎预先计算位置索引所花费的时间/空间,但我确实在意查询会非常快。
我正在考虑使用geohash作为搜索关键字,在该方法中,我将首先检查是否获得了该关键字的X个字符的结果,然后继续从关键字的末尾开始缩减字符,直到开始看到结果为止。
就我(目前非常稀疏)对地理索引技术的理解而言,与所有其他已知实现(例如R Tree和co。)相比,该方法应能够产生最快的结果(就查询时间而言)。
我正在寻找优化点邻近地理搜索时间的方法。
我的输入是lat,lng点,我正在搜索到n个最近点的一组预先计算的位置。
我不在乎预先计算位置索引所花费的时间/空间,但我确实在意查询会非常快。
我正在考虑使用geohash作为搜索关键字,在该方法中,我将首先检查是否获得了该关键字的X个字符的结果,然后继续从关键字的末尾开始缩减字符,直到开始看到结果为止。
就我(目前非常稀疏)对地理索引技术的理解而言,与所有其他已知实现(例如R Tree和co。)相比,该方法应能够产生最快的结果(就查询时间而言)。
Answers:
绝对可以。而且速度可能很快。(密集计算位也可以分配)
有几种方法,但是我一直在使用的一种方法是使用基于整数的 geohash 的有序列表,并为特定的geohash分辨率(分辨率近似于您的distance标准)找到所有最近的邻域geohash范围,然后查询这些geohash范围以获取附近点的列表。我为此使用redis和nodejs(即javascript)。Redis超级快,可以非常快速地检索有序范围,但是它不能执行SQL数据库可以执行的很多索引查询操作。
该方法在此处概述:https : //github.com/yinqiwen/ardb/wiki/Spatial-Index
但其要点是(释义链接):
您可以通过以下方法(在速度方面)进一步优化:
如果您非常关注精度,则可以对返回的结果使用圆距离/ haversine类型函数来进一步提高精度。
这是使用普通的base32地理哈希和SQL查询而不是redis的类似技术:https : //github.com/davetroy/geohash-js
我并不是要插入自己的东西,但我已经为nodejs&redis编写了一个模块,该模块非常容易实现。如果您愿意,请看一下代码:https : //github.com/arjunmehta/node-georedis
这个问题可以通过几种方式来理解。我将其解释为意味着您拥有大量点,并且打算使用坐标对给出的任意点重复探测它们,并希望获得n个与探测点最接近的点,并预先固定n个点。(原则上,如果n会变化,则可以为每个可能的n 设置一个数据结构,并在每个探针的O(1)时间中选择它:这可能需要很长的设置时间,并且需要大量RAM,但是我们被告知忽略此类担忧。)
建立所有点的n阶Voronoi图。这将平面划分为相连的区域,每个区域具有相同的n个邻居。这将情况减少到多边形点问题,该问题具有许多有效的解决方案。
使用Voronoi图的矢量数据结构,多边形中点搜索将花费O(log(n))时间。出于实际目的,只需创建图表的栅格版本,即可使O(1)的隐式系数极小。栅格中像元的值要么是(i)指向n个最近点的列表的指针,要么是(ii)该像元跨过图中两个或多个区域的指示。在(x,y)处的任意点的检验变为:
Fetch the cell value for (x,y).
If the value is a list of points, return it.
Else apply a vector point-in-polygon algorithm to (x,y).
为了实现O(1)性能,栅格网格必须足够精细,以使相对较少的探测点落入跨越多个Voronoi区域的像元中。这总是可以实现的,而且可能会为网格存储付出巨大的代价。
我完全使用geohash。我之所以这样,是因为我需要使用金字塔样式的信息系统来实现邻近搜索。在这种情况下,精度为8级的地质哈希是“基础”,并为精度为7的地质哈希形成了新的总计。等等。 。这些总数是面积,地面覆盖物的类型等。这是做一些非常花哨的事情的非常花哨的方法。
因此,第8级地理哈希将包含以下信息:
类型:草英亩:1.23
和7th,6th ..等。将包含以下信息:
grass_types:123英亩:6502
这总是以最低的精度建立的。这使我可以非常快速地进行各种有趣的统计。我还能够使用GeoJSON为每个geohash参考分配一个几何参考。
我能够编写几个函数来查找构成当前视口的最大地理哈希,然后使用这些函数来查找视口中第二大精度的地理哈希。这可以很容易地扩展到索引范围查询,无论我想要什么精度,我都会查询最小的“ 86ssaaaa”和最大的“ 86sszzzz”。
我正在使用MongoDB执行此操作。
更新2018年以及Geohash的一些数学基础或历史渊源:
对于地理散列的灵感是二进制数字简单interlave,也许那交错的十进制数字,像天真的算法优化了的C-广场。
二进制隔行扫描自然产生了Z阶曲线索引策略,Geohash发明者并未开始“寻找最佳的分形曲线”……但是,有趣的是,这种设计优化,更好的分形曲线是可能的(!)。
S2几何方法比Geohash更好,因为它使用了地球的球形拓扑(立方体),使用了可选的投影(所以所有像元都具有近似相同的形状和面积),并且因为用希尔伯特曲线进行分度比Z-订单曲线:
...我们可以做得更好...从右上角到左下角四边形的不连续性导致我们不得不分割一些我们可以连续的范围。(...)我们可以完全消除使用四叉树和希尔伯特曲线进行空间索引的所有不连续性(...)
blog.notdot.net/2009
现在它是一个免费高效的库,请参阅https://s2geometry.io
PS:还有(好)非官方精简版本为的NodeJS的s2-geometry,和许多“游乐场”,加载项和演示,为s2.sidewalklabs.com。
我建议在redis中使用GEORADIUS查询。
使用GEOADD调用推送按最合适的geohash级别分片的数据。
另外,看看这个-> ProximityHash。
给定中心坐标和半径,ProximityHash会生成一组覆盖圆形区域的地质哈希。它还有一个使用GeoRaptor的附加选项,它可以从最高级别开始迭代并直到酿造出最佳的混合物,从而在各个级别上创建最佳的地质哈希组合以表示圆。结果精度与起始geohash级别相同,但是数据大小显着减小,从而提高了速度和性能。