我需要一个免费的(开源)解决方案,给定lat / lng可以返回壁橱城市/州或邮编。 mysql不是一个选项,如果可能的话,小型轻量级数据库将是最好的。
更新:没有网络服务,即使是最小的插件也会每天带来5000万次展示,因此添加服务请求会占用响应时间。我不希望在请求上添加超过200毫秒。
我在csv中有数据库,lat / lon / zip / city / state它只是如何存储,更重要的是如何以最快的速度检索它。
答案 0 :(得分:10)
这是一个非常有趣的问题,答案很复杂。
你提到一个有纬度/经度的城市数据库,但城市不是单点,这可以在人口密集的地区产生很大的不同,城市A的大部分地区可能更接近城市B的“中心”而不是城市中心A.在一个被较小郊区包围的大城市。大城市的外围部分可能更靠近郊区的中心,而不是大城市的中心。捕捉到最近的市中心意味着地图是城市中心点的Voronoi图。这样的地图看起来不像是城市地区的实际地图。
如果你想知道一个给定纬度/经度的城市和州,你需要查询一个合适的地图,并在多边形测试中指出它是什么。这听起来计算成本很高,但它实际上是如果您使用适当的空间索引并且在编码时要小心,那就不错了。我运行一个销售此访问和其他地理查询的API访问的网站,我们的底层引擎(用Java编写)可以返回美国的包含或最近的城市,平均查询时间为3e-4秒(超过3,000个查询)每秒)。
即使我们正在销售它,我也很乐意解释它是如何工作的,因为从我们这里购买它比自己制造它更便宜,即使有说明也是如此。所以这里是:
就是这样。我打造和关闭了这个系统大约半年。我的估计是,其中至少有三个月的严格编码,这是熟悉该主题的人(因此,请注意,如果您正在做出购买或构建决策)。
答案 1 :(得分:9)
暴力:将所有数据预加载到阵列中。计算当前点与数组中每个点之间的距离(有一种方法可以使用线性代数而不是触发函数进行此计算,但我不记得它是什么,以便找到最近的点。
请在向下投票之前阅读:有很多方法可以加快像这样的暴力搜索,但我发现他们通常不值得这么麻烦。我不仅在使用此方法之前从纬度/经度找到最近的拉链,我已经在Windows Mobile应用程序中使用它(处理能力不是很强大)并且仍然实现了亚秒级搜索时间。只要你避免使用trig函数,这不是一个昂贵的过程。
更新:您可以通过将您的zip数据分配到子区域(象限,例如西北,东南等)并使用每个数据点保存区域ID来加快搜索时间。然后,在搜索中,首先确定当前位置所在的区域,并仅与这些数据点进行比较。
为了避免边界错误(例如当您的当前位置靠近其区域的边缘但实际上最接近相邻区域中的zip时),您的区域应该在某种程度上重叠。这意味着您的一些邮政记录将被复制,因此您的整体数据集将会更大。
答案 2 :(得分:3)
使用kd-tree加速最近邻搜索。无论您的平台是什么,都应该有很多免费的实现。
答案 3 :(得分:1)
它不是开源的,但也许您可以使用Google Maps API:
答案 4 :(得分:1)
你应该看看geonames。他们有一个返回XML和/或JSON的API。 另外,你可以使用他们的数据库。
答案 5 :(得分:0)
另一个线程通过MaxMind推荐mod_geoip。 它在Apache级别运行,甚至在它进入PHP / .NET / Java之前。 Maxmind geolocation apis: Apache vs PHP
答案 6 :(得分:0)
如果您同时拥有拉链的长度和纬度以及当前位置,则可以计算半径并找到该圆圈内的点。如果您设定每个邮政编码范围的假定边界,则可以加快搜索速度。
如果您可以使用SQL 2008(标准版或快速版),则可以使用Spatial data类型。
答案 7 :(得分:0)
Yahoo! Placemaker是一个免费的网络服务,可以做到这一点。它可以查找地名(“纽约市”,“白金汉宫”),但也可以使用Geo microformat来查找纬度和经度。
要使用该服务,请提交POST请求,然后返回XML:
一个小命令行示例(我隐藏了我的Yahoo!应用程序ID;您需要注册自己的代码):
$ curl -X POST -ddocumentContent='<div class="geo">GEO: <span class="latitude">37.386013</span>, <span class="longitude">-122.082932</span></div>' -ddocumentType='text/html' -dappid='your_yahoo_app_id' http://wherein.yahooapis.com/v1/document
这将返回一个非常详细的XML文档,其中一部分是:
<type>Town</type>
<name><![CDATA[Los Altos, CA, US]]></name>
它还包含以下数据:
<type>Zip</type>
<name><![CDATA[94024, Los Altos, CA, US]]></name>
我没有非常使用Placemaker,但我使用了他们的Geocoding API并且它非常快。将其与本地memcached
结合使用,用户不知道数据不是本地数据。
答案 8 :(得分:0)
查看geonames.org数据库中的源数据。
对于轻型数据库,sqlite是一个不错的选择。
geonames也可以进行网络服务,但如果您想在没有网络电话的情况下自己完成(听起来就好像这样),那么您将需要一个本地数据库。然后,您只需要进行正确的三角形计算,以计算出一对纬度/经度点之间的大圆距离(谷歌那个),然后按距离对结果进行排序。如果要在执行计算之前限制搜索半径,也可以使用边界框或半径。
如果您的本地数据库可以基于SQL(sqllite3是),则所有这些都会增加一个SQL查询,该查询会添加一堆三角形计算来计算“距离”列,也可能是一个类似的“where”子句来限制在半径或边界框内搜索。计算了查询中的距离列后,可以轻松按距离排序并添加您喜欢的任何其他条件。如果您了解ruby / rails并希望看到如何完成此操作的一个很好的示例,请查看GeoKit rails插件源代码。
答案 9 :(得分:0)
您预计离您最近的城市有多远? 50英里? 200英里? 500英里?如果两个城市几乎是等距的,那么如果你的算法选择了更接近的算法,这是否重要?您可以使用此信息来加快搜索速度。
如果您可以合理地假设距离差异很小(约250英里左右可能足够接近被认为是'小'),并且您的距离计算可能有点“模糊”,那么您可以优化'蛮力'通过限制你的搜索空间到源头的+/- 5纬度(每个纬度大约70英里,所以这给你大约350英里到北方和南方),并且+/- 5长(假设你不是在极地寻找城市,从赤道约350英里到加拿大北部约100英里。将这些范围调整为您认为适合您的问题空间的范围。
虽然触发功能将帮助您精确指示距离,但对于较小的距离,例如这些毕达哥拉斯通常足够接近“最佳猜测”答案,x = 69.1 *(sourcelat - citylat)和y = 53.0 * (sourcelong - citylong)。