redis實現查詢附近的人

2021-10-06 22:52:59 字數 1616 閱讀 1237

地球上的任何乙個位置都可以使用二維的經緯度來表示,經度範圍 [-180, 180],緯度範圍 [-90, 90]。

可以基於當前的座標節點,來劃分出乙個矩形(2r)的範圍來查詢附近的人。當兩個座標元素的距離不是很遠的時候,我們就可以簡單利用勾股定理就能夠得出他們之間的距離。但是地球不是乙個標準的球體,經緯度的密度是不一樣 的,所以我們使用勾股定理計算平方之後再求和時,需要按照一定的係數加權再進行求和。資料表可以把經緯度座標新增復合索引 ,這樣可以滿足最大優化查詢效能。

select

* from

positions

where

x > '.$lat.' - 1

and x < '.$lat.' + 1 and y > '.$lon.' - 1

and y < '.$lon.' + 1

order by

acos(

sin( ( '.$lat.' * 3.1415 ) / 180 ) * sin( ( x * 3.1415 ) / 180 ) + cos( ( '.$lat.' * 3.1415 ) / 180 ) * cos( ( x * 3.1415 ) / 180 ) * cos( ( '.$lon.' * 3.1415 ) / 180 - ( y * 3.1415 ) / 180 )

) * 6380 asc

limit 10 ';

geohash 演算法的核心思想就是把整個地球看成是乙個 二維的平面,然後把這個平面不斷地等分成乙個乙個小的方格,每乙個座標元素都位於其中的 唯一乙個方格中,等分之後的方格越小,那麼座標也就越精確。然後對每個方格進行一定順序的編碼,每乙個元素座標既能夠被唯一標識在這張被編碼的地圖上,也不至於暴露具體的位置。因為區域是共享的,我可以告訴你我就在公園附近,但是在具體的哪個地方你就無從得知了。

把任意座標變成一串二進位制的編碼,通過這個整數我們就可以還原出元素的座標,整數越長還原出來的座標值的損失程式就越小。

最後就是乙個base32 (09, az, 去掉 a/i/l/o 四個字母) 的編碼操作,讓它變成乙個字串,例如上面那一串兒就變成了 wx4g0ec1。

在 redis 中經緯度使用 52 位的整數進行編碼,放進了 zset 裡面,zset 的 value 是元素的 key,score 是 geohash的 52 位整數值。zset 的 score 雖然是浮點數,但是對於 52 位的整數值來說,它可以無損儲存。

在使用 redis 進行 geohash查詢時,redis內部結構實際上只是乙個zset(skiplist)。通過 zset 的 score 排序就可以得到座標附近的其他元素 (實際情況要複雜一些,不過這樣理解足夠了),通過將 score 還原成座標值就可以得到元素的原始座標了。

在 redis 的集群環境中,集合可能會從乙個節點遷移到另乙個節點,如果單個 key 的資料過大,會對集群的遷移工作造成較大的影響,在集群環境中單個 key 對應的資料量不宜超過 1m,否則會導致集群遷移出現卡頓現象,影響線上服務的正常執行,因此geo 的資料最好用單獨的redis 例項部署。

如果資料量過億甚至更大,就需要對 geo 資料進行拆分,按國家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按區拆分。這樣就可以顯著降低單個 zset 集合的大小。

如何實現查詢附近的人

問題 給定乙個使用者a,返回與此使用者相距小於d的所有使用者。支援geo的後端儲存有mongodb,redis等。那麼如果讓我們實現,我們應該怎麼做呢?思路 圍繞此使用者生成乙個圓形,半徑是d,返回所有被此園覆蓋的使用者。方法1 先求方,再求園。如果直接求園,每乙個使用者都要計算距離值,無法利用到索...

查詢附近的人 mongodb的實現

最近做乙個關於附近的人查詢,參考了很多資料 現在市面上主流的做法 1.用資料庫 2.用類存 3.用lucene 我選用的是用mongodb自帶的查附近的人的方法,如下 dbobject db new basicdbobject cityid json.parse dbobject near new ...

用redis獲取附近的人

geoadd 將指定的地理空間位置 緯度 經度 名稱 新增到指定的 key 中 我們用這個命令將使用者發表動態時的位置資訊記錄進 redis key longitude latitude member longitude latitude member georadius 以給定的經緯度為中心,返回...