我有一个超过15,000个纬度和经度坐标的列表。给定任何X,Y坐标,找到列表中最近坐标的最快方法是什么?
答案 0 :(得分:8)
我曾为网站做过一次。即找到距离您的邮政编码50英里的经销商。我用great circle calculation找到了北50英里,东50英里,南50英里,西50英里的坐标。这给了我一个min和max lat以及一个min和max long。从那时起,我做了一个数据库查询:
select *
from dealers
where latitude >= minlat
and latitude <= maxlat
and longitude >= minlong
and longitude <= maxlong
由于其中一些结果仍然超过50英里,我在那个小坐标列表上再次使用了great circle formula。然后我打印出列表以及距目标的距离。
当然,如果你想搜索国际日期线或两极附近的点,那么这将无效。但它适用于北美地区的搜索!
答案 1 :(得分:6)
您将需要使用名为Voronoi diagram的几何结构。这将平面划分为多个区域,每个区域一个,包含最接近每个给定点的所有点。
创建Voronoi图并安排数据结构查找的精确算法的代码太大,无法放入这个小编辑框中。 :)
@Linor:这基本上就是你在创建Voronoi图后会做的事情。但是,您可以选择与Voronoi图线紧密匹配的分割线(而不是制作矩形网格)(这样您将获得越过分割线的更少区域)。如果按照每个子图的最佳分界线递归地将Voronoi图分成两半,则可以对要查找的每个点进行树搜索。这需要预先做一些工作但以后节省时间。每次查找都是log N的顺序,其中N是点数。 16次比较比15,000好很多!
答案 2 :(得分:3)
您所描述的一般概念是nearest-neighbour search,并且有大量技术可以处理完全或近似地解决这些类型的查询。基本思想是使用空间分区技术将每个查询的O(n)复杂度降低到每个查询的(大约)O(log n)。
KD-Trees和KD-Trees的变体看起来效果很好,但四叉树也可以工作。这些搜索的质量取决于您的15,000个数据点是否是静态的(您没有向参考集添加大量数据点)。 Mount和Arya在Approximate Nearest Neighbour库上的工作既易于使用又易于理解,即使没有良好的数学基础。它还为您的查询的类型和容差提供了一些灵活性。
答案 3 :(得分:2)
这取决于你想要做多少次,以及可用的资源 - 如果你正在进行一次测试,那么O(log N)技术就是好的。如果你在服务器上做了一千次,构建一个位图查找表会更快,直接给出结果或作为第一阶段。 2GB的位图可以将整个世界的lat-lon映射到0.011度像素(赤道1.2km)的32位值,并且应该适合内存。如果您只是在单个国家/地区,或者可以排除极点,则可以使用较小的地图或更高的分辨率。对于15,000个点你可能有一个小得多的地图 - 我首先调整它的大小,作为执行lat-lon到邮政编码搜索的第一步,这需要更高的分辨率。根据要求,您可以使用映射值直接指向结果,或者使用候选项的短列表(这将允许更小的映射,但需要更多的后续处理 - 您不再在O(1)查找区域中)。
答案 4 :(得分:1)
你没有最快地指明你的意思。如果你想在不编写任何代码的情况下快速得到答案,我会给gpsbabel radius filter一个去。
答案 5 :(得分:1)
根据您的说明,我会使用几何数据结构,例如KD树或R树。 MySQL有一个SPATIAL数据类型可以做到这一点。其他语言/框架/数据库具有支持此功能的库。基本上,这种数据结构将点嵌入矩形树中,并使用半径搜索树。这应该足够快,我相信比构建Voronoi图更简单。我想有一些阈值,你更喜欢Voronoi图表的附加性能,这样你就可以为增加的复杂性付出代价。
答案 6 :(得分:1)
这可以通过几种方式解决。我首先通过生成连接最近点的Delaunay网络来解决这个问题。这可以使用开源GIS应用程序GRASS中的v.delaunay命令来完成。您可以使用GRASS中的许多network analysis modules之一完成GRASS中的问题。或者,您可以使用空闲空间RDBMS PostGIS来执行距离查询。 PostGIS空间查询比MySQL中的空间查询功能强大得多,因为它们不受BBOX操作的限制。例如:
SELECT network_id, ST_Length(geometry) from spatial_table where ST_Length(geometry) < 10;
由于您使用的是经度和纬度,因此您可能希望使用Spheroid-Distance functions。通过空间索引,PostGIS可以很好地扩展到大型数据集。
答案 7 :(得分:0)
即使您创建了voronoi图表,仍然意味着您需要将x,y坐标与所有15000个创建区域进行比较。为了使这更容易,我想到的第一件事是在可能的值上创建某种网格,这样你就可以轻松地将x和y坐标放入网格中的一个框中,如果相同的话对于区域列表,您应该快速缩小可能的候选对象(因为网格将更加矩形,区域可能位于多个网格位置)。
答案 8 :(得分:0)
Premature optimization is the root of all evil.
15K坐标不是那么多。为什么不迭代15K坐标,看看这是否真的是性能问题?你可以节省很多工作,也许它永远不会太慢甚至没有注意到。
答案 9 :(得分:0)
这些坐标分布的区域有多大?他们有多大的自由度?你需要多少准确度?如果它们相当接近,你可能会忽略这样一个事实,即地球是圆的,只是将它视为笛卡尔平面,而不是弄乱球形几何和大圆距离。当然,随着你从赤道越来越远,与纬度相比,苦读的程度变得更小,所以某种比例因子可能是合适的。
从一个相当简单的距离公式和强力搜索开始,看看它会花多长时间,如果结果足够准确,那么在你想象之前。
答案 10 :(得分:0)
感谢大家的回答。
@Tom,@ Chris Upchurch:坐标彼此非常接近,它们的面积相对较小,约为800平方公里。我想我可以假设表面是平的。我需要一遍又一遍地处理请求,响应应该更快,以便获得更多的Web体验。答案 11 :(得分:0)
网格非常简单,速度非常快。它基本上只是一个2D列表列表。每个数组条目表示属于网格单元格的点。很容易设置网格:
for each point p get cell that contains p add point to that cell's list
并且很容易看清楚:
given a query point p get cell that contains p check points in that cell (and its 8 neighbors), against query point p
阿莱霍
答案 12 :(得分:0)
只是为了反对,你的意思是距离近似还是(开车)时间?在市区,我很乐意在高速公路上行驶5英里(5分钟),而在另一个方向行驶4英里(停车20分钟)。
因此,如果它是您需要的“最接近”指标,我会查看具有旅行时间指标的GIS数据库。