我正在开发一个用户可以搜索他所在位置附近的项目的应用程序。
当用户注册我的服务时,会采用他们的长/拉特坐标(这实际上是从邮政编码中获取的,然后通过谷歌查找长/拉)。当用户添加项目时,也会发生这种情况,要求他们提供项目的zip /邮政编码,并将其转换为long / lat。
我的问题是如何使用MySQL进行查询,从用户所在位置搜索20英里,并获取该半径20英里范围内的所有项目?
答案 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)。