《Redis GEO(地理信息定位)功能》要點:
本文介紹了Redis GEO(地理信息定位)功能,希望對您有用。如果有疑問,可以聯系我們。
簡介
Redis 3.2 版本提供了GEO(地理信息定位)功能,支持存儲地理位置信息用來實現諸如附近位置、搖一搖這類依賴于地理位置信息的功能,對于需要實現這些功能的開發者來說是一大音.GEO功能是 Redis 的另一位作者Matt Stancliff 借鑒 NoSQL 數據庫 Ardb 實現的,Ardb 的作者來自中國,它提供了優秀的GEO功能.
相關命令
增加地理位置信息
GEOADD
自3.2.0可用.
時間復雜度:每添加一個元素的復雜度為 O(log(N)) , 其中 N 為鍵里面包含的位置元素數量.
語法:GEOADD key longitude latitude member [longitude latitude member ...]
說明:
longitude 、latitude 、member 分別是該地理位置的經度、緯度、成員(就是名稱).
將給定的空間元素(緯度、經度、名字)添加到指定的鍵里面. 這些數據會以有序集合的形式被儲存在鍵里面, 從而使得像 GEORADIUS 和 GEORADIUSBYMEMBER 這樣的命令可以在之后通過位置查詢取得這些元素.
GEOADD 命令以標準的 x,y 格式接受參數, 所以用戶必須先輸入經度, 然后再輸入緯度. GEOADD 能夠記錄的坐標是有限的: 非常接近兩極的區域是無法被索引的. 精確的坐標限制由 EPSG:900913 / EPSG:3785 / OSGEO:41001 等坐標系統定義, 具體如下:
有效的經度介于 -180 度至 180 度之間.
有效的緯度介于 -85.05112878 度至 85.05112878 度之間.
當用戶嘗試輸入一個超出范圍的經度或者緯度時, GEOADD 命令將返回一個錯誤.
返回值:
新添加到鍵里面的空間元素數量, 不包括那些已經存在但是被更新的元素.
示例:
# http://api.map.baidu.com/lbsapi/getpoint/index.html 這里可以獲取坐標,我們填入 天安門 香山 兩個位置的坐標
coderknock> GEOADD tour 116.404412 39.915046 TianAnMen 116.20003 40.002428 XiangShan
(integer) 2
# 添加北京電影學院、毛主席紀念堂,更新 天安門坐標(返回值不包括更新的個數)
coderknock> GEOADD tour 116.362444 39.977552 BeijingFilmAcademy 116.404269 39.909179 ChairmanMaoZedongMemorialHall 116.404412 39.915046 TianAnMen
(integer) 2
獲取地理位置
GEOPOS
自3.2.0可用.
時間復雜度:獲取每個位置元素的復雜度為 O(log(N)) , 其中 N 為鍵里面包含的位置元素數量.
語法:GEOPOS key member [member ...]
說明:
從鍵里面返回所有給定位置元素的位置(經度和緯度).
因為 GEOPOS 命令接受可變數量的位置元素作為輸入, 所以即使用戶只給定了一個位置元素, 命令也會返回數組回復.
返回值:
GEOPOS 命令返回一個數組, 數組中的每個項都由兩個元素組成: 第一個元素為給定位置元素的經度, 而第二個元素則為給定位置元素的緯度.
當給定的位置元素不存在時, 對應的數組項為空值.
示例:
# key 不存在
coderknock> GEOPOS nonKey
(empty list or set)
# 查詢天安門、毛主席紀念堂的位置信息
coderknock> GEOPOS tour TianAnMen ChairmanMaoZedongMemorialHall
1) 1) "116.40441387891769"
2) "39.915046196472751"
2) 1) "116.40426903963089"
2) "39.909178316988886"
獲取兩個地理位置的距離
GEOPOS
自3.2.0可用.
時間復雜度:O(log(N)).
語法:GEOPOS key member [member ...]
說明:
返回兩個給定位置之間的距離.
如果兩個位置之間的其中一個不存在, 那么命令返回空值.
指定單位的參數 unit 必須是以下單位的其中一個:
m 表示單位為米.
km 表示單位為千米.
mi 表示單位為英里.
ft 表示單位為英尺.
如果用戶沒有顯式地指定單位參數, 那么 GEODIST 默認使用米作為單位.
GEODIST 命令在計算距離時會假設地球為完美的球形, 在極限情況下, 這一假設最大會造成 0.5% 的誤差.
返回值:
計算出的距離會以雙精度浮點數的形式被返回. 如果給定的位置元素不存在, 那么命令返回空值.
示例:
# 查詢天安門 到 毛主席紀念堂的距離,使用默認單位 m
coderknock> GEODIST tour TianAnMen ChairmanMaoZedongMemorialHall
"652.7795"
# 查詢天安門 到 毛主席紀念堂的距離,使用單位 km
coderknock> GEODIST tour TianAnMen ChairmanMaoZedongMemorialHall km
"0.6528"
# 查詢的第二個元素不存在,返回 nil
coderknock> GEODIST tour TianAnMen non
(nil)
GEOHASH
GEOHASH
自3.2.0可用.
時間復雜度:尋找每個位置元素的復雜度為 O(log(N)) , 其中 N 為給定鍵包含的位置元素數量.
語法:GEOHASH key member [member ...]
說明:
返回一個或多個位置元素的 Geohash 表示
返回值:
一個數組, 數組的每個項都是一個 GEOHash . 命令返回的GEOHash 的位置與用戶給定的位置元素的位置一一對應.
示例:
# GEOHash 通過算法可以轉成 經緯度格式
coderknock> GEOHASH tour TianAnMen
1) "wx4g0f71gr0"
GEOHash 有如下特點:
GEO的數據類型為 zset,Redis 將所有地理位置信息的 GEOHash 存放在 zset 中.
coderknock> TYPE tour
zset
字符串越長,表示的位置更精確,例如 GEOHash 長度為9時,精度在2米左右.
GEOHash 長度精度(km)
12500
2630
378
420
52.4
60.61
70.076
80.019
90.002
兩個字符串越相似,它們之間的距離越近,Redis 利用字符串前綴匹配算法實現相關的命令.
GEOHash 編碼和經緯度是可以相互轉換的.
下面是 Java 版本的算法:
import jodd.util.Base32;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
/**
* <p> 本代碼來自 http://www.cnblogs.com/gaopeng527/p/5066983.html </p>
*
* @author 三產
* @version 1.0
* @date 2017-06-20
* @QQGroup 213732117
* @website http://www.coderknock.com
* @copyright Copyright 2017 拿客 coderknock.com All rights reserved.
* @since JDK 1.8
*/
public class GeoHash {
private static int numbits = 6 * 5; //經緯度單獨編碼長度
//32位編碼對應字符
final static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
//定義編碼映射關系
final static HashMap<Character, Integer> lookup = new HashMap<Character, Integer>();
//初始化編碼映射內容
static {
int i = 0;
for (char c : digits)
lookup.put(c, i++);
}
/**
* 對編碼后的字符串解碼
*
* @param geohash
* @return
*/
public double[] decode(String geohash) {
StringBuilder buffer = new StringBuilder();
for (char c : geohash.toCharArray()) {
int i = lookup.get(c) + 32;
buffer.append(Integer.toString(i, 2).substring(1));
}
BitSet lonset = new BitSet();
BitSet latset = new BitSet();
//偶數位,經度
int j = 0;
for (int i = 0; i < numbits * 2; i += 2) {
boolean isSet = false;
if (i < buffer.length())
isSet = buffer.charAt(i) == '1';
lonset.set(j++, isSet);
}
//奇數位,緯度
j = 0;
for (int i = 1; i < numbits * 2; i += 2) {
boolean isSet = false;
if (i < buffer.length())
isSet = buffer.charAt(i) == '1';
latset.set(j++, isSet);
}
double lon = decode(lonset, -180, 180);
double lat = decode(latset, -90, 90);
return new double[]{lat, lon};
}
/**
* 根據二進制和范圍解碼
*
* @param bs
* @param floor
* @param ceiling
* @return
*/
private double decode(BitSet bs, double floor, double ceiling) {
double mid = 0;
for (int i = 0; i < bs.length(); i++) {
mid = (floor + ceiling) / 2;
if (bs.get(i))
floor = mid;
else
ceiling = mid;
}
return mid;
}
/**
* 對經緯度進行編碼
*
* @param lat
* @param lon
* @return
*/
public String encode(double lat, double lon) {
BitSet latbits = getBits(lat, -90, 90);
BitSet lonbits = getBits(lon, -180, 180);
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < numbits; i++) {
buffer.append((lonbits.get(i)) ? '1' : '0');
buffer.append((latbits.get(i)) ? '1' : '0');
}
return base32(Long.parseLong(buffer.toString(), 2));
}
/**
* 根據經緯度和范圍,獲取對應二進制
*
* @param lat
* @param floor
* @param ceiling
* @return
*/
private BitSet getBits(double lat, double floor, double ceiling) {
BitSet buffer = new BitSet(numbits);
for (int i = 0; i < numbits; i++) {
double mid = (floor + ceiling) / 2;
if (lat >= mid) {
buffer.set(i);
floor = mid;
} else {
ceiling = mid;
}
}
return buffer;
}
/**
* 將經緯度合并后的二進制進行指定的32位編碼
*
* @param i
* @return
*/
private String base32(long i) {
char[] buf = new char[65];
int charPos = 64;
boolean negative = (i < 0);
if (!negative)
i = -i;
while (i <= -32) {
buf[charPos--] = digits[(int) (-(i % 32))];
i /= 32;
}
buf[charPos] = digits[(int) (-i)];
if (negative)
buf[--charPos] = '-';
return new String(buf, charPos, (65 - charPos));
}
public static void main(String[] args) throws Exception {
GeoHash geohash = new GeoHash();
String s = geohash.encode(39.9150413274765, 116.40440583229065);
System.out.println(s);
double[] geo = geohash.decode(s);
System.out.println(geo[0] + " " + geo[1]);
System.out.println(Arrays.toString(geohash.decode("wx4g0f71gr0")));
}
}
獲取指定位置范圍內的地理信息位置集合
GEORADIUS
自3.2.0可用.
時間復雜度:O(N+log(M)), 其中 N 為指定半徑范圍內的位置元素數量, 而 M 則是被返回位置元素的數量.
語法:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD][WITHDIST][WITHHASH][ASC|DESC][COUNT count][STORE key][STOREDIST key]
說明:
以給定的經緯度為中心, 返回鍵包含的位置元素當中, 與中心的距離不超過給定最大距離的所有位置元素.
范圍可以使用以下其中一個單位:
m 表示單位為米.
km 表示單位為千米.
mi 表示單位為英里.
ft 表示單位為英尺.
在給定以下可選項時, 命令會返回額外的信息:
WITHDIST : 在返回位置元素的同時, 將位置元素與中心之間的距離也一并返回. 距離的單位和用戶給定的范圍單位保持一致.
WITHCOORD : 將位置元素的經度和維度也一并返回.
WITHHASH : 以 52 位有符號整數的形式, 返回位置元素經過原始 geohash 編碼的有序集合分值. 這個選項主要用于底層應用或者調試, 實際中的作用并不大.
命令默認返回未排序的位置元素. 通過以下兩個參數, 用戶可以指定被返回位置元素的排序方式:
ASC : 根據中心的位置, 按照從近到遠的方式返回位置元素.
DESC : 根據中心的位置, 按照從遠到近的方式返回位置元素.
在默認情況下, GEORADIUS 命令會返回所有匹配的位置元素. 雖然用戶可以使用 COUNT <count> 選項去獲取前 N 個匹配元素, 但是因為命令在內部可能會需要對所有被匹配的元素進行處理, 所以在對一個非常大的區域進行搜索時, 即使只使用 COUNT 選項去獲取少量元素, 命令的執行速度也可能會非常慢. 但是從另一方面來說, 使用 COUNT 選項去減少需要返回的元素數量, 對于減少帶寬來說仍然是非常有用的.
STORE key :將返回結果的地理位置信息保存到指定鍵.
STOREDIST key :將返回結果離中心節點的距離保存到指定鍵.
返回值:
GEORADIUS 命令返回一個數組, 具體來說:
在沒有給定任何 WITH 選項的情況下, 命令只會返回一個像 ["New York","Milan","Paris"] 這樣的線性(linear)列表.
在指定了 WITHCOORD 、 WITHDIST 、 WITHHASH 等選項的情況下, 命令返回一個二層嵌套數組, 內層的每個子數組就表示一個元素.
在返回嵌套數組時, 子數組的第一個元素總是位置元素的名字. 至于額外的信息, 則會作為子數組的后續元素, 按照以下順序被返回:
以浮點數格式返回的中心與位置元素之間的距離, 單位與用戶指定范圍時的單位一致.
geohash 整數.
由兩個元素組成的坐標,分別為經度和緯度.
示例:
# 查看 tour 中距離北京南站 100 km 以內的景點
coderknock> GEORADIUS tour 116.385871 39.871977 100 km
1) "XiangShan"
2) "BeijingFilmAcademy"
3) "ChairmanMaoZedongMemorialHall"
4) "TianAnMen"
# 查看 tour 中距離北京南站 10 km 以內的景點同時顯示其經緯度
coderknock> GEORADIUS tour 116.385871 39.871977 10 km WITHCOORD
1) 1) "ChairmanMaoZedongMemorialHall"
2) 1) "116.40426903963089"
2) "39.909178316988886"
2) 1) "TianAnMen"
2) 1) "116.40441387891769"
2) "39.915046196472751"
# 查看 tour 中距離北京南站 20 km 以內的景點同時顯示其經緯度以及距離北京南站的距離(這里的單位是 km)
coderknock> GEORADIUS tour 116.385871 39.871977 20 km WITHCOORD WITHDIST
1) 1) "BeijingFilmAcademy"
2) "11.9116"
3) 1) "116.36244267225266"
2) "39.97755242026205"
2) 1) "ChairmanMaoZedongMemorialHall"
2) "4.4256"
3) 1) "116.40426903963089"
2) "39.909178316988886"
3) 1) "TianAnMen"
2) "5.0450"
3) 1) "116.40441387891769"
2) "39.915046196472751"
# 查看 tour 中距離北京南站 20 km 以內的景點同時顯示其經緯度以及距離北京南站的距離(這里的單位是 km)并且按從近到遠排序
coderknock> GEORADIUS tour 116.385871 39.871977 20 km WITHCOORD WITHDIST ASC
1) 1) "ChairmanMaoZedongMemorialHall"
2) "4.4256"
3) 1) "116.40426903963089"
2) "39.909178316988886"
2) 1) "TianAnMen"
2) "5.0450"
3) 1) "116.40441387891769"
2) "39.915046196472751"
3) 1) "BeijingFilmAcademy"
2) "11.9116"
3) 1) "116.36244267225266"
2) "39.97755242026205"
# 查看 tour 中距離北京南站 20 km 以內的景點同時顯示其經緯度以及距離北京南站的距離(這里的單位是 km)并且按從遠到近排序
coderknock> GEORADIUS tour 116.385871 39.871977 20 km WITHCOORD WITHDIST DESC
1) 1) "BeijingFilmAcademy"
2) "11.9116"
3) 1) "116.36244267225266"
2) "39.97755242026205"
2) 1) "TianAnMen"
2) "5.0450"
3) 1) "116.40441387891769"
2) "39.915046196472751"
3) 1) "ChairmanMaoZedongMemorialHall"
2) "4.4256"
3) 1) "116.40426903963089"
2) "39.909178316988886"
# 查看 tour 中距離北京南站 20 km 以內的景點同時顯示其經緯度以及距離北京南站的距離(這里的單位是 km)并且按從遠到近排序 并且顯示 geohash 整數
coderknock> GEORADIUS tour 116.385871 39.871977 20 km WITHCOORD WITHDIST DESC WITHHASH
1) 1) "BeijingFilmAcademy"
2) "11.9116"
3) (integer) 4069880657711258
4) 1) "116.36244267225266"
2) "39.97755242026205"
2) 1) "TianAnMen"
2) "5.0450"
3) (integer) 4069885555136394
4) 1) "116.40441387891769"
2) "39.915046196472751"
3) 1) "ChairmanMaoZedongMemorialHall"
2) "4.4256"
3) (integer) 4069885371962385
4) 1) "116.40426903963089"
2) "39.909178316988886"
# 查看 tour 中距離北京南站 20 km 以內的景點同時顯示其經緯度以及距離北京南站的距離(這里的單位是 km)并且按從遠到近排序 并且顯示 geohash 的前兩個元素
coderknock> GEORADIUS tour 116.385871 39.871977 20 km WITHCOORD WITHDIST DESC WITHHASH COUNT 2
1) 1) "BeijingFilmAcademy"
2) "11.9116"
3) (integer) 4069880657711258
4) 1) "116.36244267225266"
2) "39.97755242026205"
2) 1) "TianAnMen"
2) "5.0450"
3) (integer) 4069885555136394
4) 1) "116.40441387891769"
2) "39.915046196472751"
# 使用 STORE 或者 STOREDIST 不允許使用 出 COUNT 以為的其他選項
coderknock> GEORADIUS tour 116.385871 39.871977 20 km WITHCOORD WITHDIST DESC WITHHASH COUNT 2 STORE posKey STOREDIST distKey
(error) ERR STORE option in GEORADIUS is not compatible with WITHDIST, WITHHASH and WITHCOORDS options
# 存儲
coderknock> GEORADIUS tour 116.385871 39.871977 20 km STORE posKey STOREDIST distKey COUNT 2
(integer) 2
coderknock> ZRANGE distKey 0 -1 WITHSCORES
1) "ChairmanMaoZedongMemorialHall"
2) "4.4256428962580543"
3) "TianAnMen"
4) "5.0450138622984122"
coderknock> TYPE posKey
none
# 同時使用 STORE STOREDIST 只有最后一個選項生效
coderknock> GEORADIUS tour 116.385871 39.871977 20 km STORE posKey
(integer) 3
coderknock> TYPE posKey
zset
# 這里位置信息存儲的是 geohash 整數
coderknock> ZRANGE posKey 0 -1 WITHSCORES
1) "BeijingFilmAcademy"
2) "4069880657711258"
3) "ChairmanMaoZedongMemorialHall"
4) "4069885371962385"
5) "TianAnMen"
6) "4069885555136394"
# 上面存儲的位置信息可以直接使用
coderknock> GEORADIUS posKey 116.385871 39.871977 20 km WITHCOORD WITHDIST DESC WITHHASH COUNT 2
1) 1) "BeijingFilmAcademy"
2) "11.9116"
3) (integer) 4069880657711258
4) 1) "116.36244267225266"
2) "39.97755242026205"
2) 1) "TianAnMen"
2) "5.0450"
3) (integer) 4069885555136394
4) 1) "116.40441387891769"
2) "39.915046196472751"
GEORADIUSBYMEMBER
自3.2.0可用.
時間復雜度:O(log(N)+M), 其中 N 為指定范圍之內的元素數量, 而 M 則是被返回的元素數量.
語法:GEORADIUSBYMEMBER key member radius m|km|ft|mi[WITHCOORD][WITHDIST][WITHHASH][COUNT count][ASC|DESC][STORE key][STOREDIST key]
說明:
這個命令和 GEORADIUS 命令一樣, 都可以找出位于指定范圍內的元素, 但是 GEORADIUSBYMEMBER 的中心點是由給定的位置元素決定的, 而不是像 GEORADIUS 那樣, 使用輸入的經度和緯度來決定中心點.
關于 GEORADIUSBYMEMBER 命令的更多信息, 請參考 GEORADIUS 命令的文檔.
返回值:
一個數組, 數組中的每個項表示一個范圍之內的位置元素.
示例:
coderknock> GEORADIUSBYMEMBER tour TianAnMen 100 km
1) "XiangShan"
2) "BeijingFilmAcademy"
3) "ChairmanMaoZedongMemorialHall"
4) "TianAnMen"
刪除地理位置信息
GEO 沒有提供刪除成員的命令,但是因為 GEO 的底層實現是 zset ,所以可以借用 ZREM 命令實現對地理位置信息的刪除.
查詢全部 GEO
GEO 沒有提供查詢全部成員的命令,但是因為 GEO 的底層實現是 zset ,所以可以借用 ZRANGE 等命令實現對地理位置信息的查詢.
coderknock> ZRANGE tour 0 -1 WITHSCORES
1) "XiangShan"
2) "4069880147829102"
3) "BeijingFilmAcademy"
4) "4069880657711258"
5) "ChairmanMaoZedongMemorialHall"
6) "4069885371962385"
7) "TianAnMen"
8) "4069885555136394"
歡迎參與《Redis GEO(地理信息定位)功能》討論,分享您的想法,維易PHP學院為您提供專業教程。
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/9265.html