店铺数据批量导入 Redis GEO 详解
这段代码的核心目标是:把数据库里的店铺数据,按类型分组后,批量写入 Redis 的 GEO 结构,为后续"附近店铺"查询做准备。
一、整体流程概览

二、逐行代码拆解
1. 环境准备
java
@Resource
private StringRedisTemplate stringRedisTemplate;
注入 StringRedisTemplate,用于操作 Redis,尤其是 GEO 相关命令。
2. 主方法 loadShopData()
java
@Test
void loadShopData(){
// 1. 查询店铺信息
List<Shop> list = shopService.list();
-
调用
shopService.list()从数据库中查询所有店铺。 -
得到
List<Shop>,包含所有店铺的ID、类型ID、经纬度等信息。
3. 按店铺类型分组
java
// 2. 把店铺分组,按照typeId分组,typeId一致的放到一个集合
Map<Long, List<Shop>> map = list.stream()
.collect(Collectors.groupingBy(Shop::getTypeId));
-
使用 Java 8 Stream 的
Collectors.groupingBy,按Shop::getTypeId(店铺类型ID)分组。 -
结果:
Map<Long, List<Shop>>,Key 是typeId,Value 是该类型下的所有店铺列表。
4. 遍历分组,批量写入 Redis
java
// 3. 分批完成写入Redis
for (Map.Entry<Long, List<Shop>> entry : map.entrySet()) {
// 3.1 获取类型id
Long typeId = entry.getKey();
String key = "shop:geo:" + typeId;
// 3.2 获取同类型的店铺的集合
List<Shop> value = entry.getValue();
List<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>(value.size());
// 3.3 构建GeoLocation对象
for (Shop shop : value) {
locations.add(new RedisGeoCommands.GeoLocation<>(
shop.getId().toString(), // member:店铺ID
new Point(shop.getX(), shop.getY()) // 经纬度
));
}
// 3.4 批量写入Redis GEO
stringRedisTemplate.opsForGeo().add(key, locations);
}
一、逐段关键解释
1. map.entrySet()
-
所属:
java.util.Map接口的方法 -
作用:把
Map转成一个「键值对集合」,方便for-each遍历 -
业务含义:遍历按
typeId分组后的店铺数据,拿到每一组的typeId和该类型下的所有店铺
2. RedisGeoCommands.GeoLocation
-
所属:Spring Data Redis 提供的地理位置实体类
-
用途:专门给 Redis GEO 功能封装数据,只存两个东西:
-
name:成员名称(这里存店铺 ID,后续查询时可直接拿到) -
point:坐标点(经度 + 纬度)
-
3. List<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>(shops.size());
-
含义:创建一个
List集合,名字叫locations,只能装GeoLocation类型的对象 -
通俗理解:一个专门装地理位置的盒子,初始容量设为店铺数量,避免扩容开销
4. locations.add(new RedisGeoCommands.GeoLocation<>(...))
-
含义:创建一个新的
GeoLocation对象(单个店铺的地理位置),然后add放进上面的locations集合里 -
通俗理解:把一个个 "地理位置" 放进 "盒子" 里,准备批量写入 Redis
5. stringRedisTemplate.opsForGeo().add(key, locations);
-
作用:一次性把
locations盒子里的所有数据,批量写入 Redis GEO 集合 -
优势:比单条写入减少多次网络 IO,大幅提升导入效率
6.关键细节:
-
Redis Key 设计 :
shop:geo:{typeId},不同类型的店铺存储在不同的 GEO 集合中,后续查询时按类型筛选更高效。 -
GeoLocation对象:-
member:店铺ID(后续查询结果中返回的标识) -
Point:店铺的经纬度(x, y)
-
-
批量写入优化 :先构建好所有
GeoLocation对象,再一次性调用add(key, locations),避免多次网络IO,大幅提升导入效率。
三、核心技术点:Redis GEO
Redis GEO 是专门用于存储和查询地理位置数据的数据结构,核心命令包括:
-
GEOADD key longitude latitude member:添加地理位置 -
GEORADIUS key longitude latitude radius:按半径查询附近的成员
这段代码中,我们把每个类型的店铺都存入了对应 shop:geo:{typeId} 的 GEO 集合中,后续就可以直接用 GEORADIUS 命令,查询指定经纬度附近的该类型店铺。
四、总结
这段代码将数据库中的所有店铺按类型分组,批量构建为 GeoLocation 对象,并一次性写入 Redis GEO 结构,为后续实现"附近店铺"查询功能做数据准备。