您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關 Java 中利用 redis 實現 LBS 服務的示例的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
前言
LBS(基于位置的服務) 服務是現在移動互聯網中比較常用的功能。例如外賣服務中常用的我附近的店鋪的功能,通常是以用戶當前的位置坐標為基礎,查詢一定距離范圍類的店鋪,按照距離遠近進行倒序排序。
自從 redis 4 版本發布后, lbs 相關命令正式內置在 redis 的發行版中。要實現上述的功能,主要用到 redis geo 相關的兩個命令
GEOADD 和 GEORADIOUS
命令描述
GEOADD
GEOADD key longitude latitude member [longitude latitude member ...]
這個命令將指定的地理空間位置(緯度、經度、名稱)添加到指定的 key 中。
有效的經度從-180度到180度。
有效的緯度從-85.05112878度到85.05112878度。
當坐標位置超出上述指定范圍時,該命令將會返回一個錯誤。
該命令可以一次添加多個地理位置點
GEORADIOUS
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
這個命令以給定的經緯度為中心, 返回鍵包含的位置元素當中, 與中心的距離不超過給定最大距離的所有位置元素。
范圍可以使用以下其中一個單位:
m 表示單位為米。
km 表示單位為千米。
mi 表示單位為英里。
ft 表示單位為英尺。
在給定以下可選項時, 命令會返回額外的信息:
WITHDIST: 在返回位置元素的同時, 將位置元素與中心之間的距離也一并返回。 距離的單位和用戶給定的范圍單位保持一致。
WITHCOORD: 將位置元素的經度和維度也一并返回。
WITHHASH: 以 52 位有符號整數的形式, 返回位置元素經過原始 geohash 編碼的有序集合分值。 這個選項主要用于底層應用或者調試, 實際中的作用并不大。
ASC: 根據中心的位置, 按照從近到遠的方式返回位置元素。
DESC: 根據中心的位置, 按照從遠到近的方式返回位置元素。
在默認情況下, GEORADIUS 命令會返回所有匹配的位置元素。 雖然用戶可以使用 COUNT <count> 選項去獲取前 N 個匹配元素
接口定義
package com.x9710.common.redis; import com.x9710.common.redis.domain.GeoCoordinate; import com.x9710.common.redis.domain.Postion; import java.util.List; public interface LBSService { /** * 存儲一個位置 * * @param postion 增加的位置對象 * @throws Exception */ boolean addPostion(Postion postion); /** * 查詢以指定的坐標為中心,指定的距離為半徑的范圍類的所有位置點 * * @param center 中心點位置 * @param distinct 最遠距離,單位米 * @param asc 是否倒序排序 * @return 有效的位置 */ List<Postion> radious(String type, GeoCoordinate center, Long distinct, Boolean asc); }
實現的接口
package com.x9710.common.redis.impl; import com.x9710.common.redis.LBSService; import com.x9710.common.redis.RedisConnection; import com.x9710.common.redis.domain.GeoCoordinate; import com.x9710.common.redis.domain.Postion; import redis.clients.jedis.GeoRadiusResponse; import redis.clients.jedis.GeoUnit; import redis.clients.jedis.Jedis; import redis.clients.jedis.params.geo.GeoRadiusParam; import java.util.ArrayList; import java.util.List; public class LBSServiceRedisImpl implements LBSService { private RedisConnection redisConnection; private Integer dbIndex; public void setRedisConnection(RedisConnection redisConnection) { this.redisConnection = redisConnection; } public void setDbIndex(Integer dbIndex) { this.dbIndex = dbIndex; } public boolean addPostion(Postion postion) { Jedis jedis = redisConnection.getJedis(); try { return (1L == jedis.geoadd(postion.getType(), postion.getCoordinate().getLongitude(), postion.getCoordinate().getLatitude(), postion.getId())); } finally { if (jedis != null) { jedis.close(); } } } public List<Postion> radious(String type, GeoCoordinate center, Long distinct, Boolean asc) { List<Postion> postions = new ArrayList<Postion>(); Jedis jedis = redisConnection.getJedis(); try { GeoRadiusParam geoRadiusParam = GeoRadiusParam.geoRadiusParam().withCoord().withDist(); if (asc) { geoRadiusParam.sortAscending(); } else { geoRadiusParam.sortDescending(); } List<GeoRadiusResponse> responses = jedis.georadius(type, center.getLongitude(), center.getLatitude(), distinct.doubleValue(), GeoUnit.M, geoRadiusParam); if (responses != null) { for (GeoRadiusResponse response : responses) { Postion postion = new Postion(response.getMemberByString(), type, response.getCoordinate().getLongitude(), response.getCoordinate().getLatitude()); postion.setDistinct(response.getDistance()); postions.add(postion); } } } finally { if (jedis != null) { jedis.close(); } } return postions; } }
測試用例
package com.x9710.common.redis.test; import com.x9710.common.redis.RedisConnection; import com.x9710.common.redis.domain.GeoCoordinate; import com.x9710.common.redis.domain.Postion; import com.x9710.common.redis.impl.CacheServiceRedisImpl; import com.x9710.common.redis.impl.LBSServiceRedisImpl; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.util.List; /** * LBS服務測試類 * * @author 楊高超 * @since 2017-12-28 */ public class RedisLBSTest { private CacheServiceRedisImpl cacheService; private LBSServiceRedisImpl lbsServiceRedis; private String type = "SHOP"; private GeoCoordinate center; @Before public void before() { RedisConnection redisConnection = RedisConnectionUtil.create(); lbsServiceRedis = new LBSServiceRedisImpl(); lbsServiceRedis.setDbIndex(15); lbsServiceRedis.setRedisConnection(redisConnection); Postion postion = new Postion("2017122801", type, 91.118970, 29.654210); lbsServiceRedis.addPostion(postion); postion = new Postion("2017122802", type, 116.373472, 39.972528); lbsServiceRedis.addPostion(postion); postion = new Postion("2017122803", type, 116.344820, 39.948420); lbsServiceRedis.addPostion(postion); postion = new Postion("2017122804", type, 116.637920, 39.905460); lbsServiceRedis.addPostion(postion); postion = new Postion("2017122805", type, 118.514590, 37.448150); lbsServiceRedis.addPostion(postion); postion = new Postion("2017122806", type, 116.374766, 40.109508); lbsServiceRedis.addPostion(postion); center = new GeoCoordinate(); center.setLongitude(116.373472); center.setLatitude(39.972528); } @Test public void test10KMRadious() { List<Postion> postions = lbsServiceRedis.radious(type, center, 1000 * 10L, true); Assert.assertTrue(postions.size() == 2 && exist(postions, "2017122802") && exist(postions, "2017122803")); } @Test public void test50KMRadious() { List<Postion> postions = lbsServiceRedis.radious(type, center, 1000 * 50L, true); Assert.assertTrue(postions.size() == 4 && exist(postions, "2017122802") && exist(postions, "2017122803") && exist(postions, "2017122806") && exist(postions, "2017122804")); } private boolean exist(List<Postion> postions, String key) { if (postions != null) { for (Postion postion : postions) { if (postion.getId().equals(key)) { return true; } } } return false; } @Before public void after() { RedisConnection redisConnection = RedisConnectionUtil.create(); cacheService = new CacheServiceRedisImpl(); cacheService.setDbIndex(15); cacheService.setRedisConnection(redisConnection); cacheService.delObject(type); } }
測試結果
LBS 服務測試結果
感謝各位的閱讀!關于“ Java 中利用 redis 實現 LBS 服務的示例”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。