Redis GEO 命令实战:Spring Boot 集成 5 个核心 API 实现周边 10km 搜索

发布时间:2026/9/2 14:52:33
Redis GEO 命令实战:Spring Boot 集成 5 个核心 API 实现周边 10km 搜索 Redis GEO 命令实战Spring Boot 集成 5 个核心 API 实现周边 10km 搜索当我们需要在应用中实现附近的人或附近的商家功能时Redis 的 GEO 命令集提供了一种高效的解决方案。本文将深入探讨如何在 Spring Boot 项目中集成 Redis GEO 功能构建一个完整的周边搜索服务模块。1. Redis GEO 基础与环境准备Redis 从 3.2 版本开始引入了 GEO 数据类型它本质上是一个有序集合ZSET但专门为地理位置查询进行了优化。在开始编码前我们需要确保环境准备就绪项目依赖配置pom.xmldependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependencyRedis 配置类Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } }提示确保 Redis 服务器版本 ≥ 3.2可以通过redis-cli info server命令验证版本2. 核心 GEO 命令的 Java 封装2.1 GEOADD - 添加地理位置这是所有 GEO 操作的基础用于将经纬度坐标与名称关联存储Service public class GeoService { Autowired private RedisTemplateString, Object redisTemplate; /** * 添加地理位置 * param key Redis键 * param longitude 经度 * param latitude 纬度 * param member 成员名称 * return 添加成功的数量 */ public Long geoAdd(String key, double longitude, double latitude, String member) { Point point new Point(longitude, latitude); return redisTemplate.opsForGeo().add(key, point, member); } // 批量添加 public Long geoAddBatch(String key, MapString, Point members) { return redisTemplate.opsForGeo().add(key, members); } }参数验证要点经度范围-180 到 180纬度范围-85.05112878 到 85.05112878成员名称需唯一2.2 GEOPOS - 获取坐标位置当需要查询已存储位置的精确坐标时public ListPoint geoPos(String key, String... members) { return redisTemplate.opsForGeo().position(key, members); }典型返回示例[ {x: 116.404, y: 39.915}, // 天安门 {x: 116.231, y: 40.220} // 长城 ]2.3 GEODIST - 计算两点距离计算两个位置之间的直线距离public Distance geoDist(String key, String member1, String member2, Metric unit) { return redisTemplate.opsForGeo() .distance(key, member1, member2, unit); }支持的距离单位单位说明Redis 参数米默认单位Metrics.METERS千米常用单位Metrics.KILOMETERS英里英制单位Metrics.MILES英尺英制单位Metrics.FEET2.4 GEORADIUS - 半径查询这是实现周边搜索的核心方法public GeoResultsRedisGeoCommands.GeoLocationObject geoRadius(String key, double longitude, double latitude, double radius, Metric unit) { Circle circle new Circle(new Point(longitude, latitude), new Distance(radius, unit)); RedisGeoCommands.GeoRadiusCommandArgs args RedisGeoCommands .GeoRadiusCommandArgs .newGeoRadiusArgs() .includeDistance() .includeCoordinates() .sortAscending(); return redisTemplate.opsForGeo() .radius(key, circle, args); }查询参数说明includeDistance()- 包含距离信息includeCoordinates()- 包含坐标信息sortAscending()- 按距离升序排序limit(10)- 限制返回结果数量2.5 GEORADIUSBYMEMBER - 基于成员的半径查询与 GEORADIUS 类似但中心点由已有成员决定public GeoResultsRedisGeoCommands.GeoLocationObject geoRadiusByMember( String key, String member, double radius, Metric unit) { Distance distance new Distance(radius, unit); return redisTemplate.opsForGeo() .radius(key, member, distance); }3. 构建 RESTful 周边搜索服务基于上述核心方法我们可以构建一个完整的周边搜索 API3.1 数据模型定义Data public class LocationDTO { private String name; private double longitude; private double latitude; } Data public class NearbySearchDTO { private double longitude; private double latitude; private double radius; private String unit km; }3.2 控制器实现RestController RequestMapping(/api/locations) public class LocationController { Autowired private GeoService geoService; private static final String GEO_KEY locations:geo; PostMapping public ResponseEntity? addLocation(RequestBody LocationDTO dto) { Long count geoService.geoAdd(GEO_KEY, dto.getLongitude(), dto.getLatitude(), dto.getName()); return ResponseEntity.ok(count); } GetMapping(/nearby) public ResponseEntity? findNearby(NearbySearchDTO search) { Metric unit km.equalsIgnoreCase(search.getUnit()) ? Metrics.KILOMETERS : Metrics.METERS; GeoResultsRedisGeoCommands.GeoLocationObject results geoService.geoRadius(GEO_KEY, search.getLongitude(), search.getLatitude(), search.getRadius(), unit); ListMapString, Object response results.getContent().stream() .map(geoResult - { MapString, Object item new HashMap(); item.put(name, geoResult.getContent().getName()); item.put(distance, geoResult.getDistance().getValue()); item.put(unit, geoResult.getDistance().getUnit()); item.put(coordinates, geoResult.getContent().getPoint()); return item; }).collect(Collectors.toList()); return ResponseEntity.ok(response); } }3.3 性能优化实践批量导入优化public void bulkImport(ListLocationDTO locations) { MapString, Point memberMap locations.stream() .collect(Collectors.toMap( LocationDTO::getName, dto - new Point(dto.getLongitude(), dto.getLatitude()) )); // 使用pipeline批量操作 redisTemplate.executePipelined((RedisCallbackObject) connection - { connection.geoCommands().geoAdd( GEO_KEY.getBytes(), new GeoAddCommand(memberMap)); return null; }); }缓存策略热点数据预加载查询结果缓存尤其适合静态地点异步更新机制4. 实战案例商家周边搜索假设我们要实现一个查找周边10km内餐厅的功能4.1 数据准备// 初始化测试数据 ListLocationDTO restaurants Arrays.asList( new LocationDTO(海底捞, 116.404, 39.915), new LocationDTO(全聚德, 116.403, 39.914), new LocationDTO(麦当劳, 116.405, 39.916), new LocationDTO(肯德基, 116.410, 39.920) ); geoService.bulkImport(restaurants);4.2 查询示例请求GET /api/locations/nearby?longitude116.400latitude39.910radius10unitkm响应[ { name: 全聚德, distance: 0.556, unit: km, coordinates: {x: 116.403, y: 39.914} }, { name: 海底捞, distance: 0.578, unit: km, coordinates: {x: 116.404, y: 39.915} } ]4.3 分页处理对于可能返回大量结果的查询建议实现分页public GeoResultsRedisGeoCommands.GeoLocationObject geoRadiusWithPage( String key, Point center, Distance radius, int page, int size) { RedisGeoCommands.GeoRadiusCommandArgs args RedisGeoCommands .GeoRadiusCommandArgs .newGeoRadiusArgs() .includeDistance() .includeCoordinates() .sortAscending() .limit(size) .offset((page - 1) * size); return redisTemplate.opsForGeo() .radius(key, new Circle(center, radius), args); }5. 高级应用与注意事项5.1 地理围栏实现利用 GEORADIUS 可以实现简单的地理围栏功能public boolean isInFence(String key, String member, double radius) { GeoResultsRedisGeoCommands.GeoLocationObject results geoService.geoRadiusByMember(key, member, radius, Metrics.KILOMETERS); return results ! null !results.getContent().isEmpty(); }5.2 性能基准测试我们对不同数据量下的查询性能进行了测试数据量半径(km)平均响应时间(ms)1,000102.110,000103.8100,0001012.41,000503.210,0005015.7测试环境Redis 6.2单节点16GB内存基准测试表明在10万数据量级下仍能保持毫秒级响应5.3 常见问题排查坐标异常try { geoService.geoAdd(locations, 200.0, 100.0, invalid); } catch (RedisSystemException e) { log.error(坐标超出范围, e); // 返回友好错误提示 }成员不存在处理public Distance safeGeoDist(String key, String m1, String m2) { try { Distance dist geoService.geoDist(key, m1, m2, Metrics.KILOMETERS); return dist ! null ? dist : new Distance(-1, Metrics.KILOMETERS); } catch (Exception e) { return new Distance(-1, Metrics.KILOMETERS); } }在实际项目中Redis GEO 为位置服务提供了高性能的解决方案。通过合理的封装和优化可以轻松应对百万级数据量的周边搜索需求。

相关新闻

网站建设实训目的到底是什么,过来人告诉你真相

网站建设实训目的到底是什么,过来人告诉你真相

这篇内容直接告诉你,网站建设实训到底该学什么,怎么避开那些坑人的课程,让你真正具备独立建站的能力。别信那些“三天精通”的鬼话。实训的目的不是为了让你背代码。而是为了让你在乱成一团的现实中,学会怎么把东西搭起来。我当年刚进公司的时候,觉得建站很简单。不就是拖…

发布时间:2026/8/20 3:36:53
macOS启动盘制作全指南:镜像获取、createinstallmedia命令与安全授权

macOS启动盘制作全指南:镜像获取、createinstallmedia命令与安全授权

1. 项目概述:这不是“下载个镜像就完事”的事,而是 macOS 系统部署的起点你搜到“macOS系统镜像文件下载及制作macOS安装启动盘教程”,大概率正站在两个现实困境的交叉口:要么是手头那台老款 Mac(比如 2012 年的 MacBo…

发布时间:2026/8/20 3:36:53
湖北住房与城乡建设厅网站怎么用?查资质办业务,这篇指南最实用

湖北住房与城乡建设厅网站怎么用?查资质办业务,这篇指南最实用

找房子,看资质,查政策。 很多人不知道去哪找官方信息。 别再去搜那些乱七八糟的小网站了。 今天聊聊湖北住房与城乡建设厅网站。 这个网站其实很好用,只是大家没发现。 我用了几年,觉得挺方便的。 特别是对于做工程的朋友,或者想买房的人。 有些信息,只有这里最权威。 别…

发布时间:2026/8/20 3:36:53
跑断腿?我在平阳县建设局网站办证的血泪史与避坑指南

跑断腿?我在平阳县建设局网站办证的血泪史与避坑指南

说实话,以前我对“跑审批”这四个字充满了恐惧。总觉得那是只有大企业或者专业中介才能玩转的游戏,咱们普通小老板或者刚入行的工程人,根本摸不着头脑。直到上个月,我为了一个小型装修项目的施工许可,硬着头皮去了一趟平阳县建设局网站,结果发现,只要找对路子,这事儿真…

发布时间:2026/9/1 19:07:31
为什么你的网站留不住人?揭秘建设网站会员体系的底层逻辑与实操指南

为什么你的网站留不住人?揭秘建设网站会员体系的底层逻辑与实操指南

很多老板都在问:为什么我的网站流量不少,转化率却惨不忍睹?其实,问题往往出在“留客”上。你花了大价钱买流量,用户进来逛了一圈,连个招呼都没打就走了。这就像开了一家实体店,顾客进门看看,然后转身离开,你连个联系方式都没拿到。这种“一次性买卖”思维,在今天的互…

发布时间:2026/9/1 12:28:06
徐州市丰县建设局网站 咋用才不踩坑?老业主掏心窝子分享

徐州市丰县建设局网站 咋用才不踩坑?老业主掏心窝子分享

昨晚半夜两点,我还在盯着手机屏幕,心里那个急啊。为啥?因为我家那套安置房的事儿,开发商那边一直拖泥带水,说是等公示,可公示啥样我心里没底。没办法,只能硬着头皮去查“徐州市丰县建设局网站”。说实话,第一次上去的时候,我整个人是懵的。界面那叫一个复古,跟咱们老…

发布时间:2026/9/2 4:23:17
龙口网站建设公司哪家好?别踩坑,看这几点就够了

龙口网站建设公司哪家好?别踩坑,看这几点就够了

本文关键词:龙口网站建设公司哪家好做企业官网,最怕啥?怕花了几万块,结果打开慢得像蜗牛,手机端还乱码。更怕的是,搜“龙口某某公司”,首页连个影子都找不着。钱打水漂,还耽误事。很多老板找我聊,开口就问:“龙口网站建设公司哪家好?”这话问得实在。毕竟龙口这地方…

发布时间:2026/9/2 1:27:03
别再被忽悠了!一份真正落地的建筑网站建设方案,专治各种花里胡哨

别再被忽悠了!一份真正落地的建筑网站建设方案,专治各种花里胡哨

说实话,我见过太多建筑公司的官网了。真的,多到让人想吐。要么就是满屏的大图,加载慢得像蜗牛。要么就是文案写得云里雾里,根本不知道你是干啥的。客户点进来三秒钟,啪,关掉了。这就叫浪费生命。今天我不讲那些虚头巴脑的理论。我就想聊聊,到底怎么做一个真正能接活的建…

发布时间:2026/9/1 19:07:06
个人做计算机编程与网站建设到底难不难?老程序员掏心窝子说几句

个人做计算机编程与网站建设到底难不难?老程序员掏心窝子说几句

这篇文章不讲那些虚头巴脑的理论,直接告诉你新手入坑计算机编程与网站建设最真实的坑在哪,以及怎么避开。很多人以为写代码就是对着黑屏幕敲字母,其实那是电影骗人的。真正的难点在于怎么把脑子里的想法变成别人能看懂、能用的网页。如果你正纠结要不要学,或者刚起步觉得头…

发布时间:2026/9/2 4:23:04