前言
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]
这个命令以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
范围可以使用以下其中一个单位:
在给定以下可选项时, 命令会返回额外的信息:
接口定义
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 服务测试结果
后记
这样,我们通过 redis 就能简单实现一个我附近的小店的功能的 LBS服务。
代码同步发布在 GitHub 仓库中
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍如何在 Java 中实现一个 redis 缓存服务,包括了如何在 Java 中实现一个 redis 缓存服务的使用技巧和注意事项,需要的朋友参考一下 缓存服务的意义 为什么要使用缓存?说到底是为了提高系统的运行速度。将用户频繁访问的内容存放在离用户最近,访问速度最快的地方,提高用户的响应速度。一个 web 应用的简单结构如下图。 web 应用典型架构 在这个结构中,用户的请求通过用户
我使用spring-data-redis 1.0.0。
问题内容: 我实际上正在从事一个网站项目。我是Web服务的新手。我在面向对象的编程(java,c#,…)方面有4年的经验。我已经阅读了很多有关Web服务的文章,但是我的文档都没有告诉您如何使用所有技术来制作一个真正的Web服务项目。 我要做的是:1.使用Java映射到JPA的MySQL后端;2.使用Web服务来提供…的某些功能(JBoss,…有很多可能性,我不知道应该选择哪种方式)3.创建一个动态
本文向大家介绍利用Redis如何实现自动补全功能,包括了利用Redis如何实现自动补全功能的使用技巧和注意事项,需要的朋友参考一下 忘了redis从哪个版本开启,能够根据输入的部分命令前缀给出提示,即自动补全。接下来笔者介绍基于redis实现这个很酷的功能。 about sorted set 假设结果中有mara,marabel,marcela。现在我们输入mar,就能得到这三个名字,并且输出结果
null 其他信息:我们的应用程序是使用Ruby on Rails构建的,如果你知道任何好的宝石请建议。 我发现有几个问题(1,2)与此相关,但它们更广泛。即使是谷歌也帮不上忙,所以请不要把这个问题标记为重复。
本文向大家介绍如何实现 redis 事务?相关面试题,主要包含被问及如何实现 redis 事务?时的应答技巧和注意事项,需要的朋友参考一下 Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所