SpringBoot 使用 Redis Geo 实现查找附近的位置-附近的人功能
SpringBoot 使用 Redis Geo 实现查找附近的位置
6个操作命令
Redis 命令 | 描述 |
---|---|
GEOADD | 增加某个地理位置的坐标 |
GEOPOS | 获取某个地理位置的坐标 |
GEODIST | 获取两个地理位置的距离 |
GEORADIUS | 根据给定地理位置坐标获取指定范围内的地理位置集合 |
GEORADIUSBYMEMBERl | 根据给定地理位置获取指定范围内的地理位置集合 |
GEOHASH | 获取某个地理位置的 geohash 值 |
GEOADD
该命令格式:
geoadd key longitude latitude member [longitude latitude member ...]
对应例子:
redis> GEOADD cities 13.361389 38.115556 "shanghai" 15.087269 37.502669 "hangzhou"
(integer) 2
redis> GEODIST cities shanghai hangzhou
"166274.1516"
redis> GEORADIUS cities 15 37 100 km
1) "hangzhou"
redis> GEORADIUS cities 15 37 200 km
1) "shanghai"
2) "hangzhou"
redis>
geoadd
命令意思是将经度为13.361389纬度为38.115556的地点shanghai和经度为15.087269纬度为37.502669的地点hangzhou加入key为cities的 sorted set集合中。可以添加一到多个位置。
有效的经度从-180度到180度。有效的纬度从-85.05112878度到85.05112878度。当坐标位置超出上述指定范围时,该命令将会返回一个错误。
GEODIST
该命令格式:
GEODIST key member1 member2 [m|km|ft|mi]
对应例子:
GEODIST cities shanghai hangzhou
返回两点之间的距离,默认为米;
可选值:
- m for meters.
- km for kilometers.
- mi for miles.
- ft for feet.
例如:GEODIST cities shanghai hangzhou km
GEOPOS
该命令格式:
GEOPOS key member [member ...]
对应例子:
redis> GEOPOS cities shanghai hangzhou
1) 1) "13.36138933897018433"2) "38.11555639549629859"
2) 1) "15.08726745843887329"2) "37.50266842333162032"
获取某个地理位置的坐标
对于不存在的城市返回null;
redis> GEOPOS cities nonExisting
(nil)
GEORADIUS
该命令格式:
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
- radius 半径长度,必选项。后面的m、km、ft、mi、是长度单位选项,四选一。
- WITHCOORD 将位置元素的经度和维度也一并返回,非必选。
- WITHDIST 在返回位置元素的同时, 将位置元素与中心点的距离也一并返回。 距离的单位和查询单位一致,非必选。
- WITHHASH 返回位置的52位精度的Geohash值,非必选。这个我反正很少用,可能其它一些偏向底层的LBS应用服务需要这个。
- COUNT 返回符合条件的位置元素的数量,非必选。比如返回前10个,以避免出现符合的结果太多而出现性能问题。
- ASC|DESC 排序方式,非必选。默认情况下返回未排序,但是大多数我们需要进行排序。参照中心位置,从近到远使用ASC ,从远到近使用DESC。
对应例子:
redis> GEOADD cities 13.361389 38.115556 "shanghai" 15.087269 37.502669 "hangzhou"
(integer) 2
redis> GEORADIUS cities 15 37 200 km WITHDIST
1) 1) "shanghai"2) "190.4424"
2) 1) "hangzhou"2) "56.4413"
redis> GEORADIUS cities 15 37 200 km WITHCOORD
1) 1) "shanghai"2) 1) "13.36138933897018433"2) "38.11555639549629859"
2) 1) "hangzhou"2) 1) "15.08726745843887329"2) "37.50266842333162032"
redis> GEORADIUS cities 15 37 200 km WITHDIST WITHCOORD
1) 1) "shanghai"2) "190.4424"3) 1) "13.36138933897018433"2) "38.11555639549629859"
2) 1) "hangzhou"2) "56.4413"3) 1) "15.08726745843887329"2) "37.50266842333162032"
redis>
GEORADIUSBYMEMBERl
该命令格式:
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
对应例子:
redis> GEOADD cities 13.583333 37.316667 "shenzhen"
(integer) 1
redis> GEOADD cities 13.361389 38.115556 "shanghai" 15.087269 37.502669 "hangzhou"
(integer) 2
redis> GEORADIUSBYMEMBER cities shenzhen 100 km
1) "shenzhen"
2) "shanghai"
redis>
该命令与GEORADIUS完全相同,唯一的区别在于,该查询不使用经度和纬度值作为要查询的区域的中心,而是使用已存在于由排序集表示的地理空间索引中的成员的名称。
SpringBoot 使用 Redis Geo(实例)
springboot版本
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.8.RELEASE</version></parent>
redis starter
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
vo 对象定义
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CityInfo {/** 城市 */private String city;/** 经度 */private Double longitude;/** 纬度 */private Double latitude;
}
服务接口定义
/*** @author haoxiaoyong* @date created at 下午3:47 on 2020/9/18* @github https://github.com/haoxiaoyong1014* @blog www.haoxiaoyong.cn*/
public interface IGeoService {/*** 把城市信息保存到 Redis 中* @param cityInfos {@link CityInfo}* @return 成功保存的个数* */Long saveCityInfoToRedis(Collection<CityInfo> cityInfos);/*** 获取给定城市的坐标* @param cities 给定城市 key* @return {@link Point}s* */List<Point> getCityPos(String[] cities);/*** 获取两个城市之间的距离* @param city1 第一个城市* @param city2 第二个城市* @param metric {@link Metric} 单位信息, 可以是 null* @return {@link Distance}* */Distance getTwoCityDistance(String city1, String city2, Metric metric);/*** 根据给定地理位置坐标获取指定范围内的地理位置集合* @param within {@link Circle} 中心点和距离* @param args {@link RedisGeoCommands.GeoRadiusCommandArgs} 限制返回的个数和排序方式, 可以是 null* @return {@link RedisGeoCommands.GeoLocation}* */GeoResults<RedisGeoCommands.GeoLocation<String>> getPointRadius(Circle within, RedisGeoCommands.GeoRadiusCommandArgs args);/*** 根据给定地理位置获取指定范围内的地理位置集合* */GeoResults<RedisGeoCommands.GeoLocation<String>> getMemberRadius(String member, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args);/*** 获取某个地理位置的 geohash 值* @param cities 给定城市 key* @return city geohashs* */List<String> getCityGeoHash(String[] cities);
}
服务接口实现
/*** @author haoxiaoyong* @date created at 下午4:06 on 2020/9/18* @github https://github.com/haoxiaoyong1014* @blog www.haoxiaoyong.cn*/
@Service
@Slf4j
public class GeoServiceImpl implements IGeoService {private final String GEO_KEY = "ah-cities";@Autowiredprivate StringRedisTemplate redisTemplate;@Overridepublic Long saveCityInfoToRedis(Collection<CityInfo> cityInfos) {log.info("start to save city info: {}.", JSON.toJSONString(cityInfos));GeoOperations<String, String> ops = redisTemplate.opsForGeo();Set<RedisGeoCommands.GeoLocation<String>> locations = new HashSet<>();cityInfos.forEach(ci -> locations.add(new RedisGeoCommands.GeoLocation<String>(ci.getCity(), new Point(ci.getLongitude(), ci.getLatitude()))));log.info("done to save city info.");return ops.add(GEO_KEY, locations);}@Overridepublic List<Point> getCityPos(String[] cities) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();return ops.position(GEO_KEY, cities);}@Overridepublic Distance getTwoCityDistance(String city1, String city2, Metric metric) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();return metric == null ?ops.distance(GEO_KEY, city1, city2) : ops.distance(GEO_KEY, city1, city2, metric);}@Overridepublic GeoResults<RedisGeoCommands.GeoLocation<String>> getPointRadius(Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();return args == null ?ops.radius(GEO_KEY, within) : ops.radius(GEO_KEY, within, args);}@Overridepublic GeoResults<RedisGeoCommands.GeoLocation<String>> getMemberRadius(String member, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();return args == null ?ops.radius(GEO_KEY, member, distance) : ops.radius(GEO_KEY, member, distance, args);}@Overridepublic List<String> getCityGeoHash(String[] cities) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();return ops.hash(GEO_KEY, cities);}
}
测试用例
/*** @author haoxiaoyong* @date created at 下午4:22 on 2020/9/18* @github https://github.com/haoxiaoyong1014* @blog www.haoxiaoyong.cn*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {RangeApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class GeoServiceTest {/** fake some cityInfos */private List<CityInfo> cityInfos;@Autowiredprivate IGeoService geoService;@Beforepublic void init() {cityInfos = new ArrayList<>();cityInfos.add(new CityInfo("hefei", 117.17, 31.52));cityInfos.add(new CityInfo("anqing", 117.02, 30.31));cityInfos.add(new CityInfo("huaibei", 116.47, 33.57));cityInfos.add(new CityInfo("suzhou", 116.58, 33.38));cityInfos.add(new CityInfo("fuyang", 115.48, 32.54));cityInfos.add(new CityInfo("bengbu", 117.21, 32.56));cityInfos.add(new CityInfo("huangshan", 118.18, 29.43));}/*** <h2>测试 saveCityInfoToRedis 方法</h2>* */@Testpublic void testSaveCityInfoToRedis() {System.out.println(geoService.saveCityInfoToRedis(cityInfos));}/*** <h2>测试 getCityPos 方法</h2>* 如果传递的 city 在 Redis 中没有记录, 会返回什么呢 ? 例如, 这里传递的 xxx* */@Testpublic void testGetCityPos() {System.out.println(JSON.toJSONString(geoService.getCityPos(Arrays.asList("anqing", "suzhou", "xxx").toArray(new String[3]))));}/*** <h2>测试 getTwoCityDistance 方法</h2>* */@Testpublic void testGetTwoCityDistance() {System.out.println(geoService.getTwoCityDistance("hefei", "anqing", null).getValue());System.out.println(geoService.getTwoCityDistance("hefei", "anqing", Metrics.KILOMETERS).getValue());}/*** <h2>测试 getPointRadius 方法</h2>* */@Testpublic void testGetPointRadius() {Point center = new Point(cityInfos.get(0).getLongitude(), cityInfos.get(0).getLatitude());Distance radius = new Distance(140, Metrics.KILOMETERS);Circle within = new Circle(center, radius);System.out.println(JSON.toJSONString(geoService.getPointRadius(within, null)));// order by 距离 limit 2, 同时返回距离中心点的距离RedisGeoCommands.GeoRadiusCommandArgs args =RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(2).sortAscending();System.out.println(JSON.toJSONString(geoService.getPointRadius(within, args)));}/*** <h2>测试 getMemberRadius 方法</h2>* */@Testpublic void testGetMemberRadius() {Distance radius = new Distance(200, Metrics.KILOMETERS);System.out.println(JSON.toJSONString(geoService.getMemberRadius("suzhou", radius, null)));// order by 距离 limit 2, 同时返回距离中心点的距离RedisGeoCommands.GeoRadiusCommandArgs args =RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(2).sortAscending();System.out.println(JSON.toJSONString(geoService.getMemberRadius("suzhou", radius, args)));}/*** <h2>测试 getCityGeoHash 方法</h2>* */@Testpublic void testGetCityGeoHash() {System.out.println(JSON.toJSONString(geoService.getCityGeoHash(Arrays.asList("anqing", "suzhou", "xxx").toArray(new String[3]))));}
}
示例代码地址:https://github.com/haoxiaoyong1014/springboot-redis-examples/tree/master/springboot-redis-range
SpringBoot 使用 Redis Geo 实现查找附近的位置-附近的人功能相关推荐
- Redis GEO地理位置信息的应用
Redis GEO地理位置信息的应用 Redis GEO 概述 应用场景 Redis GEO命令 GEO命令演示 Redis GEO实现附近人的功能 基础类 API接口 接口实现 执行测试 Redis ...
- 基于Redis GEO(地理位置) 实现附近的人,商家等相关功能实现 使用SpringBoot Redis工具类
Redis GEO 1.基本介绍 1.Redis GEO 2.基础语法 GEOADD GEOPOS GEODIST GEORADIUS GEOHASH 2.可用于实现的功能 3.SpringBoot实 ...
- Spring Boot 2 实战:利用Redis的Geo功能实现查找附近的位置
1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...
- mysql redis geo_利用Redis的Geo功能实现查找附近的位置
1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...
- 利用Redis的Geo功能实现查找附近的位置!
1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...
- Redis 实战篇:Geo 算法查找附近的人
一.什么是面向 LBS 应用 经纬度是经度与纬度的合称组成一个坐标系统.又称为地理坐标系统,它是一种利用三度空间的球面来定义地球上的空间的球面坐标系统,能够标示地球上的任何一个位置(小数点后7位,精度 ...
- SpringBoot redis GEO 实战应用
上篇文章(Redis地理算法GEO解析和应用)我们对redis GEO算法进行解析以及相关shell命令的使用,这篇文章将带你进行实战应用. 依赖 注:jedis可以不引入,这里只是为了方便查看源码进 ...
- php reids的geo功能,Redis GEO相关命令和功能,你造吗?
Redis 是一个高性能的key-value数据库,其最大优点就是,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用.同时Redis还提供 ...
- Springboot整合redis(lettuce)
springboot 整合redis(lettuce) 首先确保电脑上装了redis.最好能用redisDesktop查看一下数据情况 redis是一款非常流行的Nosql数据库.redis的功能非常 ...
最新文章
- QIIME 2用户文档. 14数据评估和质控Evaluating and controlling(2019.7)
- 《精通正则表达式》读书笔记(1)
- 深入理解分布式技术 - 消息队列使用场景
- LOJ #6280. 数列分块入门 4-分块(区间加法、区间求和)
- mysql event执行记录_mysql event建立模板(可记录执行履历)
- kickStart脚本
- awk工具的简单使用
- 产品质量不过关怎么办?一招帮你大幅提高生产质量
- python入门第二十五天--反射 通过字符串的形式操作对象中的成员
- android 模仿今日头条ViewPager+TabLayout
- 精神污染:我们的信息处理能力即将达到极限
- 关于Shader wants normals, but the mesh doesn't have them的问题
- [附源码]Python计算机毕业设计SSM基于Yigo平台库房管理系统(程序+LW)
- app常见的专项测试以及面试题
- 1.1 什么是弹性盒子?
- 搞定Opera的中文字体显示
- ue4 玩家控制器APlayerController
- GitHub标星8,一文详解
- 树莓派4B突然连不上手机热点问题解决
- 一步一步教你写股票走势图——K线图三(添加均线)