不需要用到redis作经纬度查询,当然你做缓存除外。实际上我们在黑客马拉松就做过一个类似的项目,它的核心思想就是取出当前用户所在地点附近的用户。
我们使用的是MongoDB的Geo索引,这里有详细的介绍http://www./display/DOCS/G...。
但是我注意到你使用的是mysql,虽然MongoDB能够很方便的实现这一目标,但如果你不想迁移数据库的话,也还是有方法来实现的,当然你得有思想准备,此方法可能比较曲折。我以下要说的大部分内容都来自Mysql AB介绍实现geo search的文章。
首先我们要解决的是把经纬度之差换算成距离之差,这里面涉及到一些角度转换公式,它就是

其中d
是距离(distance),R
是地球半径。这个公式很复杂,但是我们的最终目标是把d
求出来,我们来看这个求值过程,以下是伪代码
R = 地球半径
Δlat = lat2 lat1 //纬度之差
Δlong = long2 long1 //经度之差
a = sin2(Δlat/2) + cos(lat1) * cos(lat2) * sin2(Δlong/2)
c = 2*atan2(√a, √(1a))
d = R*c
来把它转换为SQL代码,看着会有点晕,其中3956是地球半径
3956 * 2 * ASIN ( SQRT (
POWER(SIN((orig.lat - dest.lat)*pi()/180 / 2), 2) + COS(orig.lat * pi()/180) * COS(dest.lat * pi()/180) * POWER(SIN((orig.lon - dest.lon) * pi()/180 / 2), 2) ) ) as distance
OK,求值代码已经出来了,来写个SQL测试下(hotels表有三个字段hotel_name
,lat
,lon
)
# 设置当前位置的经纬度
set @orig_lat=122.4058;
set @orig_lon=37.7907;
# 设置最大搜索距离
set @dist=10;
SELECT *, 3956 * 2 * ASIN(SQRT(
POWER(SIN((@orig_lat - abs(dest.lat)) * pi()/180 / 2), 2) + COS(@orig_lat * pi()/180 ) * COS(abs(dest.lat) * pi()/180) * POWER(SIN((@orig_lon – dest.lon) *
pi()/180 / 2), 2) )) as distance FROM hotels dest
having distance < @dist ORDER BY distance limit 10;
这样你就可以把距离当前位置10
以内的的hotels全部搜索出来了。你可以用存储过程来优化这一代码,让它更加快速。
把所有的坐标都算出来,然后按照距离排序,mysql这个做法效率低下,即便是用存储过程编译下,也是很恼火的。 还是建议mongodb加geo索引来做
不知道提问者解决问题没有。 其实算出中心点以距离为半径的外切正方形内的经纬度范围效率比较高 SQL代码 {{{ declare @EARTH_RADIUS float set @EARTH_RADIUS = 6371000.00 ---地球的半径 declare @lat float declare @lng float declare @dlng float declare @dlat float declare @distance int ------距离 set @distance = 300 ----300米 set @lat =xx.xxxxx ---这个是中心地点 set @lng = xxx.xxxx ---中心地点 set @dlng = 2 * asin(sin( @distance / (2 * @EARTH_RADIUS)) / cos(@lat)) set @dlng = degrees(@dlng) set @dlat = 300/@EARTH_RADIUS set @dlng = degrees(@dlat) declare @lng1 float declare @lng2 float declare @lat1 float declare @lat2 float set @lat1 = @lat-@dlat set @lat2 = @lat+@dlat set @lng1 = @lng-@dlng set @lng2 = @lng+@dlng select @lat1,@lat2,@lng1,@lng2 SELECT lat,lng FROM place WHERE lat > @lat1 AND lat < @lat2 AND lng > @lng1 AND lng < @lng2; }}}