Answers
不需要用到redis作经纬度查询,当然你做缓存除外。实际上我们在 黑客马拉松 就做过一个 类似的项目 ,它的核心思想就是取出当前用户所在地点附近的用户。
我们使用的是MongoDB的Geo索引,这里有详细的介绍 http://www.mongodb.org/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, √(1−a)) 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全部搜索出来了。你可以用存储过程来优化这一代码,让它更加快速。
大脸兔喷喷
answered 11 years, 10 months ago