1. 程式人生 > >redis GEO地理位置命令介紹

redis GEO地理位置命令介紹

each limits 排序。 ima 字符 lex member pat uniq

GEOADD keylongitude latitude member [longitude latitude member ...]

Available since 3.2.0.

Time complexity: O(log(N)) for each item added, where N is the number of elements in the sorted set.

Adds the specified geospatial items (latitude, longitude, name) to the specified key. Data is stored into the key as a sorted set, in a way that makes it possible to later retrieve items using a query by radius with the GEORADIUS or GEORADIUSBYMEMBER commands.

The command takes arguments in the standard format x,y so the longitude must be specified before the latitude. There are limits to the coordinates that can be indexed: areas very near to the poles are not indexable. The exact limits, as specified by EPSG:900913 / EPSG:3785 / OSGEO:41001 are the following:

  • Valid longitudes are from -180 to 180 degrees.
  • Valid latitudes are from -85.05112878 to 85.05112878 degrees.

The command will report an error when the user attempts to index coordinates outside the specified ranges.

Note: there is no GEODEL command because you can use ZREM in order to remove elements. The Geo index structure is just a sorted set.

How does it work?

The way the sorted set is populated is using a technique called Geohash. Latitude and Longitude bits are interleaved in order to form an unique 52 bit integer. We know that a sorted set double score can represent a 52 bit integer without losing precision.

This format allows for radius querying by checking the 1+8 areas needed to cover the whole radius, and discarding elements outside the radius. The areas are checked by calculating the range of the box covered removing enough bits from the less significant part of the sorted set score, and computing the score range to query in the sorted set for each area.

What Earth model does it use?

It just assumes that the Earth is a sphere, since the used distance formula is the Haversine formula. This formula is only an approximation when applied to the Earth, which is not a perfect sphere. The introduced errors are not an issue when used in the context of social network sites that need to query by radius and most other applications. However in the worst case the error may be up to 0.5%, so you may want to consider other systems for error-critical applications.

Return value

Integer reply, specifically:

  • The number of elements added to the sorted set, not including elements already existing for which the score was updated.

Examples

redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEODIST Sicily Palermo Catania
"166274.1516"
redis> GEORADIUS Sicily 15 37 100 km
1) "Catania"
redis> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"
redis>

翻譯:

自3.2.0起可用。

每個添加項目的時間復雜度: O(log(N)),其中N是排序集中的元素數。

將指定的地理空間項目(緯度,經度,名稱)添加到指定的鍵。數據作為排序集存儲到密鑰中,使得可以使用GEORADIUSGEORADIUSBYMEMBER命令使用半徑查詢稍後檢索項目

該命令采用標準格式x,y的參數,因此必須在緯度之前指定經度。可以索引的坐標有限制:非常靠近極點的區域不可索引。如EPSG:900913 / EPSG:3785 / OSGEO:41001規定的具體限值如下:

  • 有效經度為-180至180度。
  • 有效緯度為-85.05112878至85.05112878度。

當用戶嘗試對指定範圍之外的坐標進行索引時,該命令將報告錯誤。

註意:沒有GEODEL命令,因為您可以使用ZREM來刪除元素。地理索引結構只是一個排序集。

它是如何工作的?

排序集的填充方式是使用名為Geohash的技術 緯度和經度位被交織,以便形成唯一的52位整數。我們知道一個排序集合的雙分可以代表一個52位整數,而不會失去精度。

該格式允許通過檢查覆蓋整個半徑所需的1 + 8區域,並丟棄半徑外的元素來進行半徑查詢。通過計算被覆蓋的區域的範圍來檢查區域,從排序的設定分數的較不重要的部分中移除足夠的位,並且計算每個區域的排序集合中的查詢的得分範圍。

它使用什麽地球模型?

它只是假設地球是一個球體,因為使用的距離公式是Haversine公式。這個公式只適用於地球的近似值,這不是一個完美的球體。當在需要通過半徑和大多數其他應用程序查詢的社交網站的上下文中使用時,引入的錯誤不是問題。然而,在最壞的情況下,錯誤可能高達0.5%,因此您可能需要考慮其他系統的錯誤關鍵應用程序。

返回值

整數回復,具體來說:

  • 添加到排序集中的元素數量,不包括已更新分數的元素

geoadd

geoadd用來增加地理位置的坐標,可以批量添加地理位置,命令格式為:

GEOADD key longitude latitude member [longitude latitude member ...]

key標識一個地理位置的集合。longitude latitude member標識了一個地理位置的坐標。longitude是地理位置的經度,latitude是地理位置的緯度。member是該地理位置的名稱。GEOADD可以批量給集合添加一批地理位置。

geopos

geopos可以獲取地理位置的坐標,可以批量獲取多個地理位置的坐標,命令格式為:

GEOPOS key member [member ...]

geodist

geodist用來獲取兩個地理位置的距離,命令格式為:

GEODIST key member1 member2 [m|km|ft|mi]

單位可以指定為以下四種類型:

  • m:米,距離單位默認為米,不傳遞該參數則單位為米。
  • km:公裏。
  • mi:英裏。
  • ft:英尺。

georadius

georadius可以根據給定地理位置坐標獲取指定範圍內的地理位置集合。命令格式為:

GEORADIUS key longitude latitude radius [m|km|ft|mi] [WITHCOORD] [WITHDIST] [ASC|DESC] [WITHHASH] [COUNT count]

longitude latitude標識了地理位置的坐標,radius表示範圍距離,距離單位可以為m|km|ft|mi,還有一些可選參數:

  • WITHCOORD:傳入WITHCOORD參數,則返回結果會帶上匹配位置的經緯度。
  • WITHDIST:傳入WITHDIST參數,則返回結果會帶上匹配位置與給定地理位置的距離。
  • ASC|DESC:默認結果是未排序的,傳入ASC為從近到遠排序,傳入DESC為從遠到近排序。
  • WITHHASH:傳入WITHHASH參數,則返回結果會帶上匹配位置的hash值。
  • COUNT count:傳入COUNT參數,可以返回指定數量的結果。

georadiusbymember

georadiusbymember可以根據給定地理位置獲取指定範圍內的地理位置集合。georadius命令傳遞的是坐標,georadiusbymember傳遞的是地理位置。georadius更為靈活,可以獲取任何坐標點範圍內的地理位置。但是大多數時候,只是想獲取某個地理位置附近的其他地理位置,使用georadiusbymember則更為方便。georadiusbymember命令格式為(命令可選參數與georadius含義一樣):

GEORADIUSBYMEMBER key member radius [m|km|ft|mi] [WITHCOORD] [WITHDIST] [ASC|DESC] [WITHHASH] [COUNT count]

geohash

geohash可以獲取某個地理位置的geohash值。geohash是將二維的經緯度轉換成字符串hash值的算法,後面會具體介紹geohash原理。可以批量獲取多個地理位置的geohash值。命令格式為:

GEOHASH key member [member ...]

redis GEO實現

redis GEO實現主要包含了以下兩項技術:

  • 1、使用geohash保存地理位置的坐標。
  • 2、使用有序集合(zset)保存地理位置的集合。

geohash

geohash的思想是將二維的經緯度轉換成一維的字符串,geohash有以下三個特點:

  • 1、字符串越長,表示的範圍越精確。編碼長度為8時,精度在19米左右,而當編碼長度為9時,精度在2米左右。
  • 2、字符串相似的表示距離相近,利用字符串的前綴匹配,可以查詢附近的地理位置。這樣就實現了快速查詢某個坐標附近的地理位置。
  • 3、geohash計算的字符串,可以反向解碼出原來的經緯度。

這三個特性讓geohash特別適合表示二維hash值。這篇文章:GeoHash核心原理解析詳細的介紹了geohash的原理,想要了解geohash實現的朋友可以參考這篇文章。

redis GEO命令實現

知道了redis使用有序集合(zset)保存地理位置數據(想了解redis有序集合的,可以參看這篇文章《有序集合對象》),以及geohash的特性,就很容易理解redis是如何實現redis GEO命令了。細心的讀者可能發現,redis沒有實現地理位置的刪除命令。不過由於GEO數據保存在zset中,可以用zrem來刪除某個地理位置。

  • geoadd命令增加地理位置的時候,會先計算地理位置坐標的geohash值,然後地理位置作為有序集合的member,geohash作為該member的score。然後使用zadd命令插入到有序集合。
  • geopos命令則先根據地理位置獲取geohash值,然後decode得到地理位置的坐標。
  • geodist命令先根據兩個地理位置各自得到坐標,然後計算兩個坐標的距離。
  • georadius和georadiusbymember使用相同的實現,georadiusbymember多了一步把地理位置轉換成對應的坐標。然後查找該坐標和周圍對應8個坐標符合距離要求的地理位置。因為geohash得到的值其實是個格子,並不是點,這樣通過計算周圍對應8個坐標就能解決邊緣問題。由於使用有序集合保存地理位置,在對地列位置基於範圍查詢,就相當於實現了zrange命令,內部的實現確實與zrange命令一致,只是geo有些特別的處理,比如獲得的某個地理位置,還需要計算該地理位置是否符合給定的距離訪問。
  • geohash則直接返回了地理位置的geohash值。

redis關於geohash使用了Ardb的geohash庫geohash-int,redis使用的geohash編碼長度為26位。可以精確到0.59m的精度。

總結

通過本文,撥開GEO身後的雲霧,可以看出redis借助了有序集合(zset)和geohash,加上redis本身實現的命令框架,可以很容易的實現地理位置相關的命令。

參考文獻:

  • geo命令文檔
  • Redis GEO 特性簡介
  • Redis GEO 源碼註釋
  • GeoHash核心原理解析
  • 深入淺出空間索引:為什麽需要空間索引
  • geohash wiki
  • WGS84 wiki
  • 離我最近之geohash算法(增加周邊鄰近編號)
  • 有序集合對象

redis GEO地理位置命令介紹