在用户的长/纬度20英里内找到long / lat

时间:2011-09-14 08:49:24

标签: python mysql geolocation latitude-longitude

我正在开发一个用户可以搜索他所在位置附近的项目的应用程序。

当用户注册我的服务时,会采用他们的长/拉特坐标(这实际上是从邮政编码中获取的,然后通过谷歌查找长/拉)。当用户添加项目时,也会发生这种情况,要求他们提供项目的zip /邮政编码,并将其转换为long / lat。

我的问题是如何使用MySQL进行查询,从用户所在位置搜索20英里,并获取该半径20英里范围内的所有项目?

6 个答案:

答案 0 :(得分:2)

假设精确度不是一个问题(采用正方形而不是圆形,并忽略地形),你可以这样做:

SELECT ... FROM ...
WHERE (ABS(firstLong - secondLong) < 20) AND (ABS(firstLat - secondLat) < 20);

如果您希望将其改成圆形,只需为距离写一个稍微复杂的数学公式:SQRT(longDelta*longDelta + latDelta*latDelta) < 20

答案 1 :(得分:2)

当您存储纬度/经度数据时,您还可以存储所谓的“地理空间索引”,它基本上是一次编码两个数据的字符串。一种这样的索引方案是Geohash algorithm,它使用一系列位来将地球细分为越来越小的盒子。

然后,当您想要按距离搜索时,首先根据地理位置缩小搜索范围,然后通过测试Euclidean distance或使用Haversine formula来过滤搜索结果。

另一种选择是使用专门用于执行此类查询的单独数据库。例如,MongoDB natively supports geospatial indexing和CouchDB可以在geocouch的帮助下完成。

回到MySQL,这个演示可能会有所帮助:Geo Distance Search with MySQL

答案 2 :(得分:1)

根据您使用的平台,有以下几种选择:

蛮力 - 获取数据库中的项目并在long / lat和项目坐标之间运行线性地理距离函数:

public decimal GeoDistance(decimal lat1, decimal lng1, decimal lat2, decimal lng2)
{
    double r = 6378.7; //km

    decimal p = (decimal)(Math.PI / 180.0);
    lat1 *= p; lat2 *= p; lng1 *= p; lng2 *= p;

    return (decimal)(r * (Math.Acos(Math.Sin((double)lat1) * Math.Sin((double)lat2) + Math.Cos((double)lat1) * Math.Cos((double)lat2) * Math.Cos((double)lng2 - (double)lng1))));
}

如果您使用的是MS SQL Server 2008(其他数据库引擎也可能支持),您可以使用geography methods

答案 3 :(得分:1)

在python中你可以使用kdtree,试试这个代码片段:

首先,您需要安装pysal

import pysal
from pysal.cg.kdtree import KDTree    

locations = [(40.702566, -73.816859),
         (40.70546, -73.810708),
         (40.709179, -73.820574),
         (40.700486, -73.807969),
         (40.694624, -73.820593),
         (40.695132, -73.820841),
         (40.694095, -73.821334),
         (40.694165, -73.822368),
         (40.695077, -73.822817),
         (40.6747769261, -73.8092618174)] 
tree = KDTree(locations, distance_metric='Arc', radius=pysal.cg.RADIUS_EARTH_MILES)
current_point = (40.709523, -73.802472)
# get all points within 1 mile of 'current_point'
indices = tree.query_ball_point(current_point, 1)
for i in indices:
    print(locations[i])

答案 4 :(得分:0)

你可能会发现我感兴趣的以前的答案非常高效:

Calculate distance between zip codes and users

"Find nearest location" by Zip/Postal Code?

希望这会有所帮助:)

答案 5 :(得分:0)

要获得高效率,您不希望对数据库进行完整扫描并计算每行的距离,您需要可以编制索引的条件。最简单的方法是计算具有最小/最大纬度和最小/最大经度的框,并使用BETWEEN排除这些范围之外的所有内容。由于您只处理美国地区(基于邮政编码),因此您无需担心+180和-180度之间的转换。

唯一剩下的问题是当条件以英里为单位时,以纬度/经度计算方框的边界。您需要将里程转换为度数。对于纬度来说这很容易,只需将360度除以地球的周长并乘以20; 0.289625度。经度更加艰难,因为它随纬度而变化,周长大致是余弦(纬度)* 24901.461; 20英里是20 * 360 /(cos(纬度)* 24901.461)。