《Redis GEO(地理信息定位)功能》要點:
本文介紹了Redis GEO(地理信息定位)功能,希望對您有用。如果有疑問,可以聯(lián)系我們。
簡介
Redis 3.2 版本提供了GEO(地理信息定位)功能,支持存儲地理位置信息用來實現(xiàn)諸如附近位置、搖一搖這類依賴于地理位置信息的功能,對于需要實現(xiàn)這些功能的開發(fā)者來說是一大音.GEO功能是 Redis 的另一位作者Matt Stancliff 借鑒 NoSQL 數(shù)據(jù)庫 Ardb 實現(xiàn)的,Ardb 的作者來自中國,它提供了優(yōu)秀的GEO功能.
相關(guān)命令
增加地理位置信息
GEOADD
自3.2.0可用.
時間復(fù)雜度:每添加一個元素的復(fù)雜度為 O(log(N)) , 其中 N 為鍵里面包含的位置元素數(shù)量.
語法:GEOADD key longitude latitude member [longitude latitude member ...]
說明:
longitude 、latitude 、member 分別是該地理位置的經(jīng)度、緯度、成員(就是名稱).
將給定的空間元素(緯度、經(jīng)度、名字)添加到指定的鍵里面. 這些數(shù)據(jù)會以有序集合的形式被儲存在鍵里面, 從而使得像 GEORADIUS 和 GEORADIUSBYMEMBER 這樣的命令可以在之后通過位置查詢?nèi)〉眠@些元素.
GEOADD 命令以標(biāo)準(zhǔn)的 x,y 格式接受參數(shù), 所以用戶必須先輸入經(jīng)度, 然后再輸入緯度. GEOADD 能夠記錄的坐標(biāo)是有限的: 非常接近兩極的區(qū)域是無法被索引的. 精確的坐標(biāo)限制由 EPSG:900913 / EPSG:3785 / OSGEO:41001 等坐標(biāo)系統(tǒng)定義, 具體如下:
有效的經(jīng)度介于 -180 度至 180 度之間.
有效的緯度介于 -85.05112878 度至 85.05112878 度之間.
當(dāng)用戶嘗試輸入一個超出范圍的經(jīng)度或者緯度時, GEOADD 命令將返回一個錯誤.
返回值:
新添加到鍵里面的空間元素數(shù)量, 不包括那些已經(jīng)存在但是被更新的元素.
示例:
# http://api.map.baidu.com/lbsapi/getpoint/index.html 這里可以獲取坐標(biāo),我們填入 天安門 香山 兩個位置的坐標(biāo)
coderknock> GEOADD tour 116.404412 39.915046 TianAnMen 116.20003 40.002428 XiangShan
(integer) 2
# 添加北京電影學(xué)院、毛主席紀(jì)念堂,更新 天安門坐標(biāo)(返回值不包括更新的個數(shù))
coderknock> GEOADD tour 116.362444 39.977552 BeijingFilmAcademy 116.404269 39.909179 ChairmanMaoZedongMemorialHall 116.404412 39.915046 TianAnMen
(integer) 2
獲取地理位置
GEOPOS
自3.2.0可用.
時間復(fù)雜度:獲取每個位置元素的復(fù)雜度為 O(log(N)) , 其中 N 為鍵里面包含的位置元素數(shù)量.
語法:GEOPOS key member [member ...]
說明:
從鍵里面返回所有給定位置元素的位置(經(jīng)度和緯度).
因為 GEOPOS 命令接受可變數(shù)量的位置元素作為輸入, 所以即使用戶只給定了一個位置元素, 命令也會返回數(shù)組回復(fù).
返回值:
GEOPOS 命令返回一個數(shù)組, 數(shù)組中的每個項都由兩個元素組成: 第一個元素為給定位置元素的經(jīng)度, 而第二個元素則為給定位置元素的緯度.
當(dāng)給定的位置元素不存在時, 對應(yīng)的數(shù)組項為空值.
示例:
# key 不存在
coderknock> GEOPOS nonKey
(empty list or set)
# 查詢天安門、毛主席紀(jì)念堂的位置信息
coderknock> GEOPOS tour TianAnMen ChairmanMaoZedongMemorialHall
1) 1) "116.40441387891769"
2) "39.915046196472751"
2) 1) "116.40426903963089"
2) "39.909178316988886"
獲取兩個地理位置的距離
GEOPOS
自3.2.0可用.
時間復(fù)雜度:O(log(N)).
語法:GEOPOS key member [member ...]
說明:
返回兩個給定位置之間的距離.
如果兩個位置之間的其中一個不存在, 那么命令返回空值.
指定單位的參數(shù) unit 必須是以下單位的其中一個:
m 表示單位為米.
km 表示單位為千米.
mi 表示單位為英里.
ft 表示單位為英尺.
如果用戶沒有顯式地指定單位參數(shù), 那么 GEODIST 默認(rèn)使用米作為單位.
GEODIST 命令在計算距離時會假設(shè)地球為完美的球形, 在極限情況下, 這一假設(shè)最大會造成 0.5% 的誤差.
返回值:
計算出的距離會以雙精度浮點數(shù)的形式被返回. 如果給定的位置元素不存在, 那么命令返回空值.
示例:
# 查詢天安門 到 毛主席紀(jì)念堂的距離,使用默認(rèn)單位 m
coderknock> GEODIST tour TianAnMen ChairmanMaoZedongMemorialHall
"652.7795"
# 查詢天安門 到 毛主席紀(jì)念堂的距離,使用單位 km
coderknock> GEODIST tour TianAnMen ChairmanMaoZedongMemorialHall km
"0.6528"
# 查詢的第二個元素不存在,返回 nil
coderknock> GEODIST tour TianAnMen non
(nil)
GEOHASH
GEOHASH
自3.2.0可用.
時間復(fù)雜度:尋找每個位置元素的復(fù)雜度為 O(log(N)) , 其中 N 為給定鍵包含的位置元素數(shù)量.
語法:GEOHASH key member [member ...]
說明:
返回一個或多個位置元素的 Geohash 表示
返回值:
一個數(shù)組, 數(shù)組的每個項都是一個 GEOHash . 命令返回的GEOHash 的位置與用戶給定的位置元素的位置一一對應(yīng).
示例:
# GEOHash 通過算法可以轉(zhuǎn)成 經(jīng)緯度格式
coderknock> GEOHASH tour TianAnMen
1) "wx4g0f71gr0"
GEOHash 有如下特點:
GEO的數(shù)據(jù)類型為 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 利用字符串前綴匹配算法實現(xiàn)相關(guān)的命令.
GEOHash 編碼和經(jīng)緯度是可以相互轉(zhuǎn)換的.
下面是 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 三產(chǎn)
* @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; //經(jīng)緯度單獨編碼長度
//32位編碼對應(yīng)字符
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'};
//定義編碼映射關(guān)系
final static HashMap<Character, Integer> lookup = new HashMap<Character, Integer>();
//初始化編碼映射內(nèi)容
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();
//偶數(shù)位,經(jīng)度
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);
}
//奇數(shù)位,緯度
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};
}
/**
* 根據(jù)二進制和范圍解碼
*
* @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;
}
/**
* 對經(jīng)緯度進行編碼
*
* @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));
}
/**
* 根據(jù)經(jīng)緯度和范圍,獲取對應(yīng)二進制
*
* @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;
}
/**
* 將經(jīng)緯度合并后的二進制進行指定的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")));
}
}
獲取指定位置范圍內(nèi)的地理信息位置集合
GEORADIUS
自3.2.0可用.
時間復(fù)雜度:O(N+log(M)), 其中 N 為指定半徑范圍內(nèi)的位置元素數(shù)量, 而 M 則是被返回位置元素的數(shù)量.
語法:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD][WITHDIST][WITHHASH][ASC|DESC][COUNT count][STORE key][STOREDIST key]
說明:
以給定的經(jīng)緯度為中心, 返回鍵包含的位置元素當(dāng)中, 與中心的距離不超過給定最大距離的所有位置元素.
范圍可以使用以下其中一個單位:
m 表示單位為米.
km 表示單位為千米.
mi 表示單位為英里.
ft 表示單位為英尺.
在給定以下可選項時, 命令會返回額外的信息:
WITHDIST : 在返回位置元素的同時, 將位置元素與中心之間的距離也一并返回. 距離的單位和用戶給定的范圍單位保持一致.
WITHCOORD : 將位置元素的經(jīng)度和維度也一并返回.
WITHHASH : 以 52 位有符號整數(shù)的形式, 返回位置元素經(jīng)過原始 geohash 編碼的有序集合分值. 這個選項主要用于底層應(yīng)用或者調(diào)試, 實際中的作用并不大.
命令默認(rèn)返回未排序的位置元素. 通過以下兩個參數(shù), 用戶可以指定被返回位置元素的排序方式:
ASC : 根據(jù)中心的位置, 按照從近到遠的方式返回位置元素.
DESC : 根據(jù)中心的位置, 按照從遠到近的方式返回位置元素.
在默認(rèn)情況下, GEORADIUS 命令會返回所有匹配的位置元素. 雖然用戶可以使用 COUNT <count> 選項去獲取前 N 個匹配元素, 但是因為命令在內(nèi)部可能會需要對所有被匹配的元素進行處理, 所以在對一個非常大的區(qū)域進行搜索時, 即使只使用 COUNT 選項去獲取少量元素, 命令的執(zhí)行速度也可能會非常慢. 但是從另一方面來說, 使用 COUNT 選項去減少需要返回的元素數(shù)量, 對于減少帶寬來說仍然是非常有用的.
STORE key :將返回結(jié)果的地理位置信息保存到指定鍵.
STOREDIST key :將返回結(jié)果離中心節(jié)點的距離保存到指定鍵.
返回值:
GEORADIUS 命令返回一個數(shù)組, 具體來說:
在沒有給定任何 WITH 選項的情況下, 命令只會返回一個像 ["New York","Milan","Paris"] 這樣的線性(linear)列表.
在指定了 WITHCOORD 、 WITHDIST 、 WITHHASH 等選項的情況下, 命令返回一個二層嵌套數(shù)組, 內(nèi)層的每個子數(shù)組就表示一個元素.
在返回嵌套數(shù)組時, 子數(shù)組的第一個元素總是位置元素的名字. 至于額外的信息, 則會作為子數(shù)組的后續(xù)元素, 按照以下順序被返回:
以浮點數(shù)格式返回的中心與位置元素之間的距離, 單位與用戶指定范圍時的單位一致.
geohash 整數(shù).
由兩個元素組成的坐標(biāo),分別為經(jīng)度和緯度.
示例:
# 查看 tour 中距離北京南站 100 km 以內(nèi)的景點
coderknock> GEORADIUS tour 116.385871 39.871977 100 km
1) "XiangShan"
2) "BeijingFilmAcademy"
3) "ChairmanMaoZedongMemorialHall"
4) "TianAnMen"
# 查看 tour 中距離北京南站 10 km 以內(nèi)的景點同時顯示其經(jīng)緯度
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 以內(nèi)的景點同時顯示其經(jīng)緯度以及距離北京南站的距離(這里的單位是 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 以內(nèi)的景點同時顯示其經(jīng)緯度以及距離北京南站的距離(這里的單位是 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 以內(nèi)的景點同時顯示其經(jīng)緯度以及距離北京南站的距離(這里的單位是 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 以內(nèi)的景點同時顯示其經(jīng)緯度以及距離北京南站的距離(這里的單位是 km)并且按從遠到近排序 并且顯示 geohash 整數(shù)
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 以內(nèi)的景點同時顯示其經(jīng)緯度以及距離北京南站的距離(這里的單位是 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 整數(shù)
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可用.
時間復(fù)雜度:O(log(N)+M), 其中 N 為指定范圍之內(nèi)的元素數(shù)量, 而 M 則是被返回的元素數(shù)量.
語法:GEORADIUSBYMEMBER key member radius m|km|ft|mi[WITHCOORD][WITHDIST][WITHHASH][COUNT count][ASC|DESC][STORE key][STOREDIST key]
說明:
這個命令和 GEORADIUS 命令一樣, 都可以找出位于指定范圍內(nèi)的元素, 但是 GEORADIUSBYMEMBER 的中心點是由給定的位置元素決定的, 而不是像 GEORADIUS 那樣, 使用輸入的經(jīng)度和緯度來決定中心點.
關(guān)于 GEORADIUSBYMEMBER 命令的更多信息, 請參考 GEORADIUS 命令的文檔.
返回值:
一個數(shù)組, 數(shù)組中的每個項表示一個范圍之內(nèi)的位置元素.
示例:
coderknock> GEORADIUSBYMEMBER tour TianAnMen 100 km
1) "XiangShan"
2) "BeijingFilmAcademy"
3) "ChairmanMaoZedongMemorialHall"
4) "TianAnMen"
刪除地理位置信息
GEO 沒有提供刪除成員的命令,但是因為 GEO 的底層實現(xiàn)是 zset ,所以可以借用 ZREM 命令實現(xiàn)對地理位置信息的刪除.
查詢?nèi)?GEO
GEO 沒有提供查詢?nèi)砍蓡T的命令,但是因為 GEO 的底層實現(xiàn)是 zset ,所以可以借用 ZRANGE 等命令實現(xiàn)對地理位置信息的查詢.
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學(xué)院為您提供專業(yè)教程。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/9265.html