Redis之GeoHash
在生活中我們有時(shí)候需要點(diǎn)外賣、騎共享單車等等,我們打開軟件找到附近餐廳、離我最近的單車,那么他們是怎么快速定位到的呢?我們把地圖看作一個(gè)二維平面,我們?cè)谀硞€(gè)點(diǎn)上然后找到附近10km內(nèi)的所有餐廳,這時(shí)候我們知道求兩點(diǎn)直接的距離是需要一個(gè)公式,且需要知道兩點(diǎn)的x,y軸坐標(biāo)才能計(jì)算出距離,通過(guò)計(jì)算出距離然后進(jìn)行排列,那么我們就能過(guò)找到離我最近的一個(gè)餐廳了。
那么這里我們考慮幾個(gè)問(wèn)題,我每次搜索的時(shí)候需要計(jì)算我離餐廳的距離,那么我們能不能把這個(gè)距離保存起來(lái)呢?如果我保存了,我下次在另一個(gè)地方那是不是還得重新計(jì)算?所以在數(shù)量級(jí)小的時(shí)候可以考慮這個(gè)做法,但是數(shù)量級(jí)起來(lái)了這個(gè)方法不是一個(gè)好的方法。
我們打開地圖發(fā)現(xiàn)地圖并不是一開始把所有的細(xì)節(jié)都顯示,比如我首先看到的是中國(guó),然后放大看到的是廣東,再放大看到的是深圳,那么我們假設(shè)這個(gè)是一個(gè)大盒子,里面有很多個(gè)小盒子,小盒子里面有很多更小的盒子,每個(gè)小盒子都用二進(jìn)制標(biāo)記比如小盒子里:00,01,10,11....
我們通過(guò)把(x,y)轉(zhuǎn)換成的編碼連接起來(lái),如上圖所示,是不是就可以把他們轉(zhuǎn)換成一個(gè)一維的線性結(jié)構(gòu),那么對(duì)于我們的排序非常有利。那么這個(gè)就是我們今天所說(shuō)的GeoHash。
GeoHash算法分為三步
第一步:把經(jīng)緯度轉(zhuǎn)換成二進(jìn)制
第二步:把二進(jìn)制的經(jīng)緯度合并
第三步:按照base32進(jìn)行編碼
Base32編碼表的其中一種如下,是用0-9、b-z(去掉a, i, l, o)這32個(gè)字母進(jìn)行編碼。具體操作是先將上一步得到的合并后二進(jìn)制轉(zhuǎn)換為10進(jìn)制數(shù)據(jù),然后對(duì)應(yīng)生成Base32碼。需要注意的是,將5個(gè)二進(jìn)制位轉(zhuǎn)換成一個(gè)base32碼。在Redis中經(jīng)緯度使用52位的整數(shù)進(jìn)行編碼,最后的結(jié)果放在zset里面,ZSet的value是元素的key,score是GeoHash的52位數(shù)值,這里注意score是一個(gè)浮點(diǎn)型,但是對(duì)于52位的整形是無(wú)損存儲(chǔ)。Redis給我們提供6個(gè)Geo命令,下面我們就開始使用這個(gè)Geo命令了
查詢
這里我們注意添加是geoadd,可以添加多個(gè)點(diǎn),刪除就是直接使用zrem即可
> geoadd name 110.50000 30.50000 zhangsan(integer) 1> geoadd name 110.60000 30.60000 lisi(integer) 1> geoadd name 120.50000 30.60000 wangwu(integer) 1> geoadd name 111.45000 29.90000 zhaoliu 111.50000 30.10000 mango(integer)?2距離
geodist 指令可以用來(lái)計(jì)算兩個(gè)元素之間的距離,攜帶集合名稱、兩個(gè)名稱和距離單位,距離單位可以是 m、 km、ml 和丘,分別代表米、干米、英里和尺。
> geodist name zhangsan mango km"105.8372"獲取元素位置
geopos 指令可以獲取
> geopos name zhangsan1) 1) "110.49999743700027" 2) "30.499999345868211"獲取元素hash值
GeoHash 可以獲取元素的經(jīng)緯度編碼字符串,上面已經(jīng)提到,它是 base32 編碼。你可以使用這個(gè)編碼值去http://geohash.org/$ {hash}上進(jìn)行直接定位,它是 GeoHash的標(biāo)準(zhǔn)編碼值。
>?geohash?name zhangsan1) "wmqtd2reke0"附近的元素
georadiusbymember指令是最為關(guān)鍵的指令之一,它可以用來(lái)查詢指定元素附近的其他元素,它的參數(shù)非常復(fù)雜 。
#### 獲取據(jù)離zhangsan20km最近的三個(gè)人> georadiusbymember name zhangsan 20 km count 3 asc1) "zhangsan"2) "lisi"####?withcoord?withdist?withhash三個(gè)可選參數(shù)> georadiusbymember name zhangsan 20 km withcoord withdist withhash count 31) 1) "zhangsan" 2) "0.0000" 3) (integer) 4028187045502241 4) 1) "110.49999743700027" 2) "30.499999345868211"2) 1) "lisi" 2) "14.6789" 3) (integer) 4028372360456825 4) 1) "110.60000091791153"??????2)?"30.599999165046462"除了georadiusbyrnember指令根據(jù)元素查詢附近的元素,Redis還提供了根據(jù)坐標(biāo)值來(lái)查詢附近的元素的指令georadius,這個(gè)指令更加有用,它可以根據(jù)用戶的定位來(lái)計(jì)算附近的餐館”等。它的參數(shù)和georadiusbyrnernber基本一致,唯一的差別是將目標(biāo)元素改成經(jīng)緯度坐標(biāo)值。
> georadius name 110.50000 30.50000 20 km count 31) "zhangsan"2) "lisi"注意:這里的GeoHash雖然好用,它實(shí)際上還是個(gè)ZSet,數(shù)據(jù)量超過(guò)一定的閾值后查詢速度會(huì)減慢,那么我們?cè)谔幚磉@些問(wèn)題的時(shí)候需要對(duì)地圖進(jìn)行切割或者進(jìn)行分塊處理。
?
?
一名正在搶救的coder
筆名:mangolove
CSDN地址:https://blog.csdn.net/mango_love
GitHub地址:https://github.com/mangoloveYu
?
總結(jié)
以上是生活随笔為你收集整理的Redis之GeoHash的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android_Exynos4412_i
- 下一篇: mongo数据库CRUD