?引言
本文參考黑馬 點(diǎn)評(píng)項(xiàng)目
在點(diǎn)評(píng)項(xiàng)目中 如何 實(shí)現(xiàn) 附近商家的查詢呢,展示出距離自己5公里內(nèi)的商戶,這樣的功能如何實(shí)現(xiàn)?
答案是可以采用Redis 來實(shí)現(xiàn),當(dāng)然可能有很多實(shí)現(xiàn)方式,本文主要介紹如何使用Redis實(shí)現(xiàn) 附近商戶的搜索功能
??廣播站
CSDN博客之星參選博主:Bug終結(jié)者
我正在參加年度博客之星評(píng)選,請(qǐng)大家?guī)臀彝镀贝蚍?,您的每一分都是?duì)我的支持與鼓勵(lì)。
鏈接:https://bbs.csdn.net/topics/611387239
感謝您的支持!??!
一、Redis GEO 數(shù)據(jù)結(jié)構(gòu)用法
?GEO基本語法、指令
GEO 就是 GeoLocation 的簡(jiǎn)寫形式,代表地理坐標(biāo)。Redis在3.2版本中加入了對(duì)GEO的支持,允許存儲(chǔ)地理坐標(biāo)信息,幫助我們根據(jù)經(jīng)緯度來檢索數(shù)據(jù)。
常見的命令
- GEOADD:添加一個(gè)地理空間信息,包含:經(jīng)度(longitude)、緯度(latitude)、值(member)
- GEODIST:計(jì)算指定的兩個(gè)點(diǎn)之間的距離并返回
- GEOHASH:將指定member的坐標(biāo)轉(zhuǎn)為hash字符串形式并返回
- GEOPOS:返回指定member的坐標(biāo)
- GEORADIUS:指定圓心、半徑,找到該圓內(nèi)包含的所有member,并按照與圓心之間的距離排序后返回。6.以后已廢棄
- GEOSEARCH:在指定范圍內(nèi)搜索member,并按照與指定點(diǎn)之間的距離排序后返回。范圍可以是圓形或矩形。6.2.新功能
- GEOSEARCHSTORE:與GEOSEARCH功能一致,不過可以把結(jié)果存儲(chǔ)到一個(gè)指定的key。 6.2.新功能
?使用GEO存儲(chǔ)經(jīng)緯度、查詢距離
本篇博文 Redis版本為 6.2版本
進(jìn)入redis 查詢 geo相關(guān)指令
使用 GEO 完成以下功能 實(shí)現(xiàn)兩點(diǎn)之間的距離查詢,以及指定范圍內(nèi)的地點(diǎn)
需求如下
- 使用 GEO 添加 北京 (天安門 116.397469 39.908821 、故宮 116.397027 39.918056、北海公園 116.389977 39.933144) 經(jīng)緯度
- 查詢 天安門 與 故宮之間的距離
- 在以上添加的地點(diǎn)中查詢 天安門廣場(chǎng) (116.397827 39.90374) 附近2公里的地點(diǎn)
GEOADD 添加
GEOPOS 查看指定地點(diǎn) 經(jīng)緯度信息
GEOHASH 查看指定地址 經(jīng)緯度HASH值
拓展: GEOPOS 和 GEOHASH 的區(qū)別在于 GEOHASH 節(jié)約了 經(jīng)緯度存儲(chǔ)的 內(nèi)存、減少不必要的內(nèi)存消耗,從而提升性能
GEODIST 查看 天安門 與故宮之間的距離
GEOSEARCH 查詢 天安門廣場(chǎng) 附近 2公里的地點(diǎn)
二、SpringBoot 整合Redis 導(dǎo)入 店鋪數(shù)據(jù) 到GEO
編寫SpringBoot 單元測(cè)試進(jìn)行導(dǎo)入Redis數(shù)據(jù)
@Resource
private IShopService shopService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
void loadShopData() {
//1. 查詢店鋪信息
List<Shop> shopList = shopService.list();
//2. 把店鋪分組,按照typeId分組、typeId一致的放在一個(gè)集合
Map<Long, List<Shop>> map = shopList.stream().collect(Collectors.groupingBy(Shop::getTypeId));
//3. 分批完成寫入redis
for (Map.Entry<Long, List<Shop>> entry : map.entrySet()) {
//3.1 獲取類型id
Long typeId = entry.getKey();
String key = RedisConstants.SHOP_GEO_KEY + typeId;
//3.2 獲取同類型的店鋪的集合
List<Shop> value = entry.getValue();
List<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>(value.size());
//3.3 寫入redis GEOADD key 經(jīng)度 維度 member
for (Shop shop : value) {
locations.add(new RedisGeoCommands.GeoLocation<>(
shop.getId().toString(),
new Point(shop.getX(), shop.getY())));
}
stringRedisTemplate.opsForGeo().add(key, locations);
}
}
運(yùn)行完畢,查看Redis即可
三、SpringBoot 整合 Redis 實(shí)現(xiàn) 附近商戶功能
??需求介紹
基于黑馬點(diǎn)評(píng)項(xiàng)目實(shí)現(xiàn) 附近商戶查詢功能
- 采用GEO 數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)附近商戶查詢
- 完成分頁功能
思路分析:
通過傳輸過來的 x、y 經(jīng)緯度,然后我們根據(jù)該經(jīng)緯度去查詢r(jià)edis中附近的商戶,查出后即可返回,進(jìn)行封裝,查出來的結(jié)果進(jìn)行循環(huán)添加至 Shop 地點(diǎn)距離,即可完成。
?核心源碼
ShopController
@GetMapping("/of/type")
public Result queryShopByType(
@RequestParam("typeId") Integer typeId,
@RequestParam(value = "current", defaultValue = "1") Integer current,
@RequestParam(value = "x", required = false) Double x,
@RequestParam(value = "y", required = false) Double y) {
return shopService.queryShopByType(typeId, current, x, y);
}
ShopService
@Override
public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
//1. 判斷是否需要坐標(biāo)查詢
if (x == null || y == null) {
// 不需要坐標(biāo)查詢,按數(shù)據(jù)庫查詢
Page<Shop> page = query()
.eq("type_id", typeId)
.page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));
// 返回?cái)?shù)據(jù)
return Result.ok(page.getRecords());
}
//2. 計(jì)算分頁參數(shù)
int form = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;
int end = current * SystemConstants.DEFAULT_PAGE_SIZE;
//3. 查詢r(jià)edis,按照距離排序、分頁 結(jié)果:shopId、distance
String key = RedisConstants.SHOP_GEO_KEY + typeId;
GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo().search(
key,
GeoReference.fromCoordinate(x, y),
new Distance(5000),
RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance().limit(end));
//4. 解析id
if (results == null) {
return Result.ok(Collections.emptyList());
}
List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = results.getContent();
//4.1 截取from => end
List<Long> ids = new ArrayList<>(content.size());
Map<String, Distance> distanceMap = new HashMap<>(content.size());
if (content.size() <= form) {
return Result.ok(Collections.emptyList());
}
content.stream().skip(form).forEach(result -> {
//4.2 獲取店鋪id
String shopIdStr = result.getContent().getName();
ids.add(Long.valueOf(shopIdStr));
//4.2 獲取距離
Distance distance = result.getDistance();
distanceMap.put(shopIdStr, distance);
});
//5. 根據(jù)id查詢shop
String idStr = StrUtil.join(",", ids);
List<Shop> shops = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();
// 循環(huán)將 商品距離放入對(duì)象距離屬性中
shops.forEach(shop -> {
shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());
});
//6. 返回結(jié)果
return Result.ok(shops);
}
進(jìn)行測(cè)試
?附近商戶效果圖
?小結(jié)
以上就是【Bug 終結(jié)者】對(duì) 微服務(wù) SpringBoot 整合 Redis 實(shí)現(xiàn)附近商戶功能 的簡(jiǎn)單介紹,附近商戶搜索,是很常見的功能,掌握GEO即可完成該類似的需求,并高質(zhì)量完成開發(fā),加油! 認(rèn)真練習(xí),提升技術(shù)。 技術(shù)改變世界?。?!
文章來源:http://www.zghlxwxcb.cn/news/detail-792283.html
如果這篇【文章】有幫助到你,希望可以給【Bug 終結(jié)者】點(diǎn)個(gè)贊??,創(chuàng)作不易,如果有對(duì)【后端技術(shù)】、【前端領(lǐng)域】感興趣的小可愛,也歡迎關(guān)注?????? 【Bug 終結(jié)者】??????,我將會(huì)給你帶來巨大的【收獲與驚喜】??????!文章來源地址http://www.zghlxwxcb.cn/news/detail-792283.html
到了這里,關(guān)于微服務(wù) SpringBoot 整合 Redis GEO 實(shí)現(xiàn)附近商戶功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!