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 实现查找附近的位置-附近的人功能相关推荐

  1. Redis GEO地理位置信息的应用

    Redis GEO地理位置信息的应用 Redis GEO 概述 应用场景 Redis GEO命令 GEO命令演示 Redis GEO实现附近人的功能 基础类 API接口 接口实现 执行测试 Redis ...

  2. 基于Redis GEO(地理位置) 实现附近的人,商家等相关功能实现 使用SpringBoot Redis工具类

    Redis GEO 1.基本介绍 1.Redis GEO 2.基础语法 GEOADD GEOPOS GEODIST GEORADIUS GEOHASH 2.可用于实现的功能 3.SpringBoot实 ...

  3. Spring Boot 2 实战:利用Redis的Geo功能实现查找附近的位置

    1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...

  4. mysql redis geo_利用Redis的Geo功能实现查找附近的位置

    1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...

  5. 利用Redis的Geo功能实现查找附近的位置!

    1. 前言 老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点.明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了.赶紧去查相关的技术选型.经过一番折腾,终于在晚上十点完成了这个需求. ...

  6. Redis 实战篇:Geo 算法查找附近的人

    一.什么是面向 LBS 应用 经纬度是经度与纬度的合称组成一个坐标系统.又称为地理坐标系统,它是一种利用三度空间的球面来定义地球上的空间的球面坐标系统,能够标示地球上的任何一个位置(小数点后7位,精度 ...

  7. SpringBoot redis GEO 实战应用

    上篇文章(Redis地理算法GEO解析和应用)我们对redis GEO算法进行解析以及相关shell命令的使用,这篇文章将带你进行实战应用. 依赖 注:jedis可以不引入,这里只是为了方便查看源码进 ...

  8. php reids的geo功能,Redis GEO相关命令和功能,你造吗?

    Redis 是一个高性能的key-value数据库,其最大优点就是,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用.同时Redis还提供 ...

  9. Springboot整合redis(lettuce)

    springboot 整合redis(lettuce) 首先确保电脑上装了redis.最好能用redisDesktop查看一下数据情况 redis是一款非常流行的Nosql数据库.redis的功能非常 ...

最新文章

  1. QIIME 2用户文档. 14数据评估和质控Evaluating and controlling(2019.7)
  2. 《精通正则表达式》读书笔记(1)
  3. 深入理解分布式技术 - 消息队列使用场景
  4. LOJ #6280. 数列分块入门 4-分块(区间加法、区间求和)
  5. mysql event执行记录_mysql event建立模板(可记录执行履历)
  6. kickStart脚本
  7. awk工具的简单使用
  8. 产品质量不过关怎么办?一招帮你大幅提高生产质量
  9. python入门第二十五天--反射 通过字符串的形式操作对象中的成员
  10. android 模仿今日头条ViewPager+TabLayout
  11. 精神污染:我们的信息处理能力即将达到极限
  12. 关于Shader wants normals, but the mesh doesn't have them的问题
  13. [附源码]Python计算机毕业设计SSM基于Yigo平台库房管理系统(程序+LW)
  14. app常见的专项测试以及面试题
  15. 1.1 什么是弹性盒子?
  16. 搞定Opera的中文字体显示
  17. ue4 玩家控制器APlayerController
  18. GitHub标星8,一文详解
  19. 树莓派4B突然连不上手机热点问题解决
  20. 一步一步教你写股票走势图——K线图三(添加均线)

热门文章

  1. Android Studio扩展显示器分屏展示多项目后窗口空白问题解决
  2. PLSQL 常用语句
  3. 聊天室程序python_Python聊天室程序(基础版)_python
  4. java实现截取视频方法
  5. 百度奖学金获得者徐立恒:执着创造价值
  6. 了解USB-HID协议
  7. Easypoi的简单教程
  8. JD token解密之旅
  9. 7 数据的表现形式——变量
  10. 爆笑笑话集锦,亲们,笑喷你