不需要用到redis作經(jīng)緯度查詢(xún),當(dāng)然你做緩存除外。實(shí)際上我們?cè)?a target="_blank" rel="nofollow" title="黑客馬拉松">黑客馬拉松就做過(guò)一個(gè)類(lèi)似的項(xiàng)目,它的核心思想就是取出當(dāng)前用戶(hù)所在地點(diǎn)附近的用戶(hù)。
我們使用的是MongoDB的Geo索引,這里有詳細(xì)的介紹http://www./display/DOCS/G...。
但是我注意到你使用的是mysql,雖然MongoDB能夠很方便的實(shí)現(xiàn)這一目標(biāo),但如果你不想遷移數(shù)據(jù)庫(kù)的話(huà),也還是有方法來(lái)實(shí)現(xiàn)的,當(dāng)然你得有思想準(zhǔn)備,此方法可能比較曲折。我以下要說(shuō)的大部分內(nèi)容都來(lái)自Mysql AB介紹實(shí)現(xiàn)geo search的文章。
首先我們要解決的是把經(jīng)緯度之差換算成距離之差,這里面涉及到一些角度轉(zhuǎn)換公式,它就是

其中d
是距離(distance),R
是地球半徑。這個(gè)公式很復(fù)雜,但是我們的最終目標(biāo)是把d
求出來(lái),我們來(lái)看這個(gè)求值過(guò)程,以下是偽代碼
R = 地球半徑
Δlat = lat2 lat1 //緯度之差
Δlong = long2 long1 //經(jīng)度之差
a = sin2(Δlat/2) + cos(lat1) * cos(lat2) * sin2(Δlong/2)
c = 2*atan2(√a, √(1a))
d = R*c
來(lái)把它轉(zhuǎn)換為SQL代碼,看著會(huì)有點(diǎn)暈,其中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,求值代碼已經(jīng)出來(lái)了,來(lái)寫(xiě)個(gè)SQL測(cè)試下(hotels表有三個(gè)字段hotel_name
,lat
,lon
)
# 設(shè)置當(dāng)前位置的經(jīng)緯度
set @orig_lat=122.4058;
set @orig_lon=37.7907;
# 設(shè)置最大搜索距離
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;
這樣你就可以把距離當(dāng)前位置10
以?xún)?nèi)的的hotels全部搜索出來(lái)了。你可以用存儲(chǔ)過(guò)程來(lái)優(yōu)化這一代碼,讓它更加快速。
把所有的坐標(biāo)都算出來(lái),然后按照距離排序,mysql這個(gè)做法效率低下,即便是用存儲(chǔ)過(guò)程編譯下,也是很惱火的。 還是建議mongodb加geo索引來(lái)做
不知道提問(wèn)者解決問(wèn)題沒(méi)有。 其實(shí)算出中心點(diǎn)以距離為半徑的外切正方形內(nèi)的經(jīng)緯度范圍效率比較高 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 ---這個(gè)是中心地點(diǎn) set @lng = xxx.xxxx ---中心地點(diǎn) 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; }}}