redis之GEO使用
寫在前面
在LBS(location based service)應用,如滴滴打車應用,需要根據用戶的位置信息來獲取某些數據,如獲取距離當前用戶指定距離范圍內的所有車輛信息,該類的應用就可以使用本文我們要學習的GEO了,接下來一起看下。
1:實戰
1.1:geoadd
添加位置信息,格式GEOADD key longitude latitude member [longitude latitude member ...],可以指定多組經度+緯度+位置名稱,如下:
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 21.2:geopos
獲取指定位置的經緯度,如果是不存在的位置則返回nil,格式GEOPOS key member [member ...],如下測試:
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2 redis> GEOPOS Sicily Palermo Catania NonExisting 1) 1) "13.36138933897018433"2) "38.11555639549629859" 2) 1) "15.08726745843887329"2) "37.50266842333162032" 3) (nil) redis>1.3:geodist
geodist 用于返回兩個給定位置之間的距離。geodist 語法格式為GEODIST key member1 member2 [m|km|ft|mi],參數說明如下:
m:米,默認單位。 km:千米。 mi:英里。 ft:英尺。如果是不存在的地點則返回nil,如下測試:
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2 redis> GEODIST Sicily Palermo Catania "166274.1516" redis> GEODIST Sicily Palermo Catania km "166.2742" redis> GEODIST Sicily Palermo Catania mi "103.3182" redis> GEODIST Sicily Foo Bar (nil)1.4:georadius
以給定的經緯度為中心,并指定距離范圍,返回該距離范圍內的所有地點信息,格式如下:
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]參數說明如下:
m:米,默認單位。 km:千米。 mi:英里。 ft:英尺。 WITHDIST: 在返回位置元素的同時, 將位置元素與中心之間的距離也一并返回。 WITHCOORD: 將位置元素的經度和緯度也一并返回。 WITHHASH: 以 52 位有符號整數的形式, 返回位置元素經過原始 geohash 編碼的有序集合分值。 這個選項主要用于底層應用或者調試, 實際中的作用并不大。 COUNT 限定返回的記錄數。 ASC: 查找結果根據距離從近到遠排序。 DESC: 查找結果根據從遠到近排序。測試如下:
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2 redis> GEORADIUS Sicily 15 37 200 km WITHDIST 1) 1) "Palermo"2) "190.4424" 2) 1) "Catania"2) "56.4413" redis> GEORADIUS Sicily 15 37 200 km WITHCOORD 1) 1) "Palermo"2) 1) "13.36138933897018433"2) "38.11555639549629859" 2) 1) "Catania"2) 1) "15.08726745843887329"2) "37.50266842333162032" redis> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD 1) 1) "Palermo"2) "190.4424"3) 1) "13.36138933897018433"2) "38.11555639549629859" 2) 1) "Catania"2) "56.4413"3) 1) "15.08726745843887329"2) "37.50266842333162032"1.5:geohash
獲取經緯度對應的geohash值,底層Set中存儲的也是該值,語法格式為GEOHASH key member [member ...],測試如下:
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2 redis> GEOHASH Sicily Palermo Catania 1) "sqc8b49rny0" 2) "sqdtr74hyu0"2:原理
我們知道,經度的范圍是[-180,180],緯度的范圍是[-90,90],我們可以將其想想為如下的一個矩形,矩形中的每個點都有一個經緯度的信息,如下圖:
但是這個圖里每一個點目前都是用經度和緯度來表示的,如果是我們能夠將矩形劃分成很多個區域,然后每個區域使用一個整數來表示,則就很容易方便查找周邊經緯度了,而redis就使用GeoHash編碼方法實現了這個需求,基本原理是二分區間,區間編碼,二分區間的意思是將經度或緯度的范圍平分為兩份,區間編碼就是對每一份給一個編碼,具體的,redis會分別對經度和緯度執行GeoHash,然后將二者的編碼合并為最終的編碼。
GeoHash會將經度和緯度劃分為N位的二進制編碼,其中N就是需要對區間劃分的次數,這里我們假設N為5來編碼,假設要編碼的經緯度是(116.37,39.86)看下這個過程:
首先對經度編碼,如果落在左區間則編碼為0,如果落在右區間則編碼為1:
二分[-180,180]為[-180,0),[0,180]左右兩個區間,116.37落在右區間,所以編碼為1 二分[0,180]為[0,90),[90,180]左右兩個區間,116.37落在右區間,所以編碼為1 二分[90,180]為[90,135),[135,180]左右兩個區間,116.37落在左區間,所以編碼為0 二分[90,135]為[90,112.5),[112.5,135]左右兩個區間,116.37落在右區間,所以編碼為1 二分[112.5,135]為[112.5,123.75),[123.75,135]左右兩個區間,116.37落在左區間,所以編碼為0所以最終的編碼是11010,該過程也可以用下圖表示:
緯度同該編碼過程,最終結果是10111,該過程可以用下圖表:
最終二者組合的規則是:從左到右偶數位依次取經度的編碼,奇數位依次取緯度的編碼,因此我們先來取經度的編碼,為1?1?0?1?0?,接著我們將其中的?,即奇數位使用緯度的編碼替換,結果就是1110011101,整個過程如下圖:
這樣,一個經緯度就會被轉換為一個整數,而相近的整數在實際的地理位置上也是更接近的,這里我們生成編碼的N如果是越大,則矩形的區域也會被劃分的越細,距離的匹配也會更加精確。
其實GEO底層使用的數據結構正是Set,而DeoHash的結果是作為其score的,這樣當我們查找某地附近的地點時,就可以直接上前向后直接查找了。
3:打車場景
假定用戶打車場景中根據用戶所在定位查找車輛,先模擬庫中的車輛信息:
127.0.0.1:6379> GEOADD car:location 13.361389 38.115556 "張師傅" 15.087269 37.502669 "李師傅" 17.087269 35.502669 "劉師傅" 117.087269 65.502669 "孫小姐"現在顧客芒果小朋友要打車,假設經緯度是13.361399 38.115565,則查找其5公里范圍內的車輛,如下:
127.0.0.1:6379> GEORADIUS car:location 13.361399 38.115565 5 km 張師傅可以看到只有張師傅符合要求,那么就可以給張師傅派單了。
寫在后面
參考文章列表:
Redis GEO 。
總結
以上是生活随笔為你收集整理的redis之GEO使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用SketchUp草图大师创建第一
- 下一篇: 回归预测 | MATLAB实现SVR(支