41人参与 • 2025-05-09 • Redis
这个功能将使用到redis中的geo这种数据结构来实现。
geo就是geolocation的简写形式,代表地理坐标。redis在3.2版本中加入到了对geo的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据,常见命令如下:
添加下面几条数据:
# 1. 添加地理空间数据 geoadd stations 116.378248 39.865275 "北京南站" 116.42803 39.903738 "北京站" 116.322287 39.893729 "北京西站"
计算北京西站到北京站的距离
# 2. 计算北京西站到北京站的距离 geodist stations "北京西站" "北京站" km
搜索天安门(116.397904 39.909005)附近10km内的所有火车站,并按照距离升序排序
# 3. 搜索天安门附近10km内的火车站并按距离排序 geosearch stations fromlonlat 116.397904 39.909005 byradius 10 km asc
//在serviceimpl中(简单演示) @autowired private stringredistemplate stringredistemplate; @override public result queryshopbytype(integer typeid, integer current, double x, double y) { // 1. 判断是否需要基于地理位置查询 if (x == null || y == null) { // 不需要地理坐标查询时,直接按类型分页查询数据库 page<shop> page = query() .eq("type_id", typeid) // 按店铺类型筛选 .page(new page<>(current, systemconstants.default_page_size)); // 分页查询 // 返回查询结果 return result.ok(page.getrecords()); } // 2. 需要地理查询时,计算分页参数 int from = (current - 1) * systemconstants.default_page_size; // 起始偏移量 int end = current * systemconstants.default_page_size; // 结束位置 // 3. 从redis中查询附近店铺id(geo查询) string key = "shop:geo:" + typeid; // geo数据存储的key // 执行geo搜索:以(x,y)为中心,5000米半径范围内,查询end数量的店铺 georesults<redisgeocommands.geolocation<string>> results = stringredistemplate.opsforgeo().search( key, georeference.fromcoordinate(x, y), // 中心点坐标 new distance(5000), // 搜索半径(5公里) redisgeocommands.geosearchcommandargs.newgeosearchargs() .includedistance() // 包含距离信息 .limit(end) // 限制返回数量 ); // 4. 处理查询结果并获取店铺详情 if (results == null) { return result.ok(collections.emptylist()); // 无结果时返回空列表 } list<georesult<redisgeocommands.geolocation<string>>> list = results.getcontent(); if (list.size() <= from) { return result.ok(collections.emptylist()); // 结果不足时分页返回空 } // 收集店铺id和距离信息 list<long> ids = new arraylist<>(list.size()); map<string, distance> distancemap = new hashmap<>(list.size()); // 跳过前from条记录(分页处理),然后处理剩余记录 list.stream().skip(from).foreach(result -> { string id = result.getcontent().getname(); // 获取店铺id ids.add(long.valueof(id)); distancemap.put(id, result.getdistance()); // 存储店铺距离 }); // 根据id批量查询店铺详情(保持id顺序) string strids = strutil.join(",", ids); list<shop> shops = query() .in("id", ids) // 按id列表查询 .last("order by field(id," + strids + ")") // 保持redis返回的顺序 .list(); // 为每个店铺设置距离信息 for (shop shop : shops) { shop.setdistance(distancemap.get(shop.getid().tostring()).getvalue()); } // 5. 返回带距离信息的店铺列表 return result.ok(shops); }
排序方式
.sortascending() // 按距离升序排序(从近到远) .sortdescending() // 按距离降序排序(从远到近)
返回内容控制
.includedistance() // 在结果中包含距离信息 .includecoordinates() // 在结果中包含坐标信息 .includename() // 在结果中包含成员名称(默认包含)
结果限制
.limit(50) // 限制返回结果数量(可用于简单分页)
单位设置
.includedistance().withdistance(metrics.kilometers) // 指定距离单位 //支持的单位: //metrics.kilometers(千米) //metrics.miles(英里) //metrics.feet(英尺) //metrics.meters(米)
georeference 的三种主要形式
//1.fromcoordinate(x, y) //作用:通过经纬度坐标指定中心点 //示例: georeference.fromcoordinate(116.404, 39.915) // 北京天安门坐标 //2.frommember(membername) //作用:通过 redis中已存储的geo成员名称指定中心点 //示例: georeference.frommember("北京站") // 以已存储的"北京站"坐标为中心 //3.fromstring("x,y") //作用:通过字符串格式的坐标指定中心点 //示例: georeference.fromstring("116.404,39.915")
如下为完整示例:
georesults<redisgeocommands.geolocation<string>> results = stringredistemplate.opsforgeo().search( "shop:geo:1", georeference.fromcoordinate(116.397904, 39.909005), new distance(5, metrics.kilometers), redisgeocommands.geosearchcommandargs.newgeosearchargs() .includedistance() // 包含距离 .includecoordinates() // 包含坐标 .sortascending() // 按距离升序 .limit(100) // 最多返回100条 .withdistance(metrics.kilometers) // 距离单位为千米 );
对于 redis 6.2 及以上版本,还可以使用:
矩形范围搜索
.bybox(width, height, metrics.kilometers) // 矩形范围搜索
存储搜索结果
.store("result-key") // 将结果存储到指定key .storedist("result-key") // 存储带距离的结果
到此这篇关于基于redis实现-附近商铺查询的文章就介绍到这了,更多相关redis附近商铺查询内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论