前言
- Redis除了常見的五種數(shù)據(jù)類型之外,其實還有一些少見的數(shù)據(jù)結構,如Geo,HyperLogLog等。雖然它們少見,但是作用卻不容小覷。本文將介紹Geo指令的語法和使用場景。
Geo介紹
- Geo是"geolocation"的縮寫,即地理定位器,顧名思義就是記錄地理位置信息,用來進行地址位置排序的數(shù)據(jù)結構。所以它場景的應用場景便是尋找附近的人,最佳路線推薦等等。
- 說到地址位置排序,不得不提地理位置距離排序算法GeoHash算法,Redis也使用了這個算法。簡單來說,這個算法就是將某地點的經(jīng)度和緯度進行編碼之后,成為的一維整數(shù),整數(shù)越接近,兩個地點也就越接近。通過整數(shù)可以還原出經(jīng)緯度坐標,整數(shù)越長,還原出來的坐標損失程度就越小。GeoHash算法會繼續(xù)對這個整數(shù)做一次base32編碼,使其變成字符串。
- 于是在使用Geo數(shù)據(jù)結構時,可以簡單地理解為,它只是一個zset,score是元素地址經(jīng)過GeoHash算法得到的52位整數(shù)(在Redis里面,經(jīng)緯度使用52位的整數(shù)進行編碼),value存放該元素。
Geo指令使用
-
向Geo中添加地理空間信息:geoadd key 經(jīng)度 緯度 具體元素
geoadd restaurant 95 20 "沙縣小吃" geoadd restaurant 96 19 "肯德基" 120 27 "麥當勞"
-
返回指定兩個元素的距離:geodist key 元素1 元素2 距離單位
geodist restaurant "沙縣小吃" "肯德基" km
-
獲取元素坐標:geopos key 元素1 … 元素n
geopos restaurant "麥當勞" geopos restaurant "沙縣小吃" "肯德基"
-
獲取指定元素坐標的hash字符串:geohash key 元素1
geohash restaurant "沙縣小吃"
獲取到的hash值可以到 http://geohash.org/${hash} 上進行定位,得到經(jīng)緯度坐標
-
指定圓心半徑,找到該圓范圍內(nèi)的所有元素,并按與圓心距離排序后返回:georadius key 經(jīng)度 緯度 半徑 單位 withdist/withcoord/withhash count n des/asc
georadius restaurant 95 21 100 km withdist count 3 asc # 查找經(jīng)度95 緯度21的地點半徑100公里以內(nèi)的餐館,正序輸出三個餐館
withdist: 同時返回該元素與圓心的距離,距離單位為georadius指令指定的單位
withhash: 同時返回52位整數(shù)編碼后的字符串
withcoord: 同時返回該元素的經(jīng)緯度坐標
使用場景:附近的人
-
需求:實現(xiàn)查看附近的人功能。
-
實現(xiàn)方案:使用geo數(shù)據(jù)結構,將用戶的位置經(jīng)緯度保存在geo中,然后對這些信息進行查詢。
-
代碼實現(xiàn):代碼中saveUserLocation()方法負責添加用戶位置信息,在添加時使用outOfChina()方法判斷做位置檢驗,是否用戶位置在國內(nèi),不在國內(nèi)就不保存了,deleteUserLocation()方法負責刪除某用戶的位置信息,getNearByLocation()方法負責查詢某個地方附近的用戶。文章來源:http://www.zghlxwxcb.cn/news/detail-806582.html
public class NearbyPeopleDemo { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1"); jedis.del(LOCATION_KEY); double lon ; double lat ; //向redis中存放用戶的地址,隨機生成一萬個用戶。 for(int i = 0;i<10000;i++){ lon = Math.random()*(138-72+1)+72; lat = Math.random()*(55-0+1); //判斷該位置是否屬于中國,不屬于就不加了 if(!outOfChina(lon,lat)) { saveUserLocation("用戶"+i, lon, lat, jedis); } } System.out.println("添加用戶位置信息完畢!"); System.out.println("距離經(jīng)度100,緯度35位置100km以內(nèi)的人有哪些:"+ getNearByLocation(100, 35, 100, jedis)); } private static final String LOCATION_KEY = "location"; /** * 保存用戶位置信息 * @param userId 用戶id * @param longitude 經(jīng)度 * @param latitude 緯度 * @param jedis */ public static void saveUserLocation(String userId, double longitude, double latitude, Jedis jedis){ jedis.geoadd(LOCATION_KEY,longitude,latitude,userId); } /** * 根據(jù)用戶id刪除用戶位置信息,采用zset的刪除方式刪除即可 * @param userId * @param jedis */ public static void deleteUserLocation(String userId,Jedis jedis){ jedis.zrem(LOCATION_KEY,userId); } /** * 查詢附近的人 * @param longitude 經(jīng)度 * @param latitude 緯度 * @param radius 半徑 * @param jedis * @return */ public static List<String> getNearByLocation(double longitude, double latitude,double radius,Jedis jedis){ List<GeoRadiusResponse> georadius = jedis.georadius(LOCATION_KEY, longitude, latitude, radius, GeoUnit.KM); return georadius.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()); } /** * 判斷經(jīng)緯度是否超過了中國 * @param longitude 經(jīng)度 * @param latitude 緯度 * @return */ public static boolean outOfChina(double longitude,double latitude) { if (longitude < 72.004 || longitude > 137.8347) return true; if (latitude < 0.8293 || latitude > 55.8271) return true; return false; } }
-
測試結果:我們在main方法中,隨機生成一萬個用戶位置信息,保存在redis中,之后調(diào)用getNearByLocation()方法查找距離經(jīng)度100,緯度35的位置100km以內(nèi)的人有哪些,運行結果如下:
文章來源地址http://www.zghlxwxcb.cn/news/detail-806582.html
參考文獻
- 《91.Redis深度歷險 核心原理與應用實踐》–錢文品
到了這里,關于Redis--Geo指令的語法和使用場景舉例(附近的人功能)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!