国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

如何使用Redis實現(xiàn)附近商家查詢

這篇具有很好參考價值的文章主要介紹了如何使用Redis實現(xiàn)附近商家查詢。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

如何使用Redis實現(xiàn)附近商家查詢,redis,數(shù)據(jù)庫,緩存,java

????宏夏Coding網(wǎng)站,致力于為編程學習者、互聯(lián)網(wǎng)求職者提供最需要的內(nèi)容!網(wǎng)站內(nèi)容包括求職秘籍,葵花寶典(學習筆記),資源推薦等內(nèi)容。在線閱讀:https://hongxiac.com????

導讀

在日常生活中,我們經(jīng)常能看見查詢附近商家的功能。

常見的場景有,比如你在點外賣的時候,就可能需要按照距離查詢附近幾百米或者幾公里的商家。

本文將介紹如何使用Redis實現(xiàn)按照距離查詢附近商戶的功能,并以SpringBoot項目作為舉例。

如何使用Redis實現(xiàn)附近商家查詢,redis,數(shù)據(jù)庫,緩存,java

想知道這樣的功能是如何實現(xiàn)的嗎?接著往下看吧!

Redis地理位置功能

Redis是一種高性能的鍵值存儲數(shù)據(jù)庫,具有快速讀寫能力和豐富的數(shù)據(jù)結(jié)構(gòu)支持。在Redis 3.2版本之后,它引入了地理位置(Geospatial)功能,使其可以輕松處理與地理位置相關的數(shù)據(jù)。

地理位置功能的核心數(shù)據(jù)結(jié)構(gòu)是有序集合(Sorted Set),它將元素與分數(shù)(score)關聯(lián)起來。在地理位置功能中,分數(shù)表示地理位置的經(jīng)度和緯度,而元素則是一個標識符,比如商戶的ID。

我們只需要在數(shù)據(jù)庫中存儲商家的經(jīng)緯度,以商家id作為key,經(jīng)緯度作為value存入redis中,就可以通過redis命令來獲得以某一個點為圓心一定范圍內(nèi)的商家,以及他們之間的距離。

如何使用Redis實現(xiàn)附近商家查詢,redis,數(shù)據(jù)庫,緩存,java

常用命令

1. GEOADD:將地理位置添加到有序集合中
? ?使用GEOADD命令,可以將一個或多個地理位置添加到有序集合中。語法如下:

GEOADD key longitude latitude member [longitude latitude member ...]

示例:
? ?GEOADD stores 116.404 39.915 "storeA"
? ?GEOADD stores 116.418 39.917 "storeB"

2. GEODIST:計算兩個位置之間的距離

? GEODIST命令用于計算兩個位置之間的距離,可以指定單位(米、千米、英里、英尺等)。


? ?GEODIST key member1 member2 [unit]

? ?示例:

? ?GEODIST stores storeA storeB km

3. GEORADIUS:按照距離查詢位置范圍內(nèi)的元素
? ?GEORADIUS命令用于在指定的地理位置范圍內(nèi)查詢元素。它可以按照經(jīng)緯度坐標和半徑來查詢,還可以限制返回的結(jié)果數(shù)量。

?GEORADIUS key longitude latitude radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key]

? ?示例:
?
? ?GEORADIUS stores 116.408 39.916 1 km WITHDIST COUNT 5
? 

4. GEOHASH:獲取位置的geohash值
? ?GEOHASH命令用于獲取指定位置的geohash值,geohash是一種將地理位置編碼成字符串的方法,可以用于快速近似的位置計算。

?GEOHASH key member [member ...]

? ?示例:

? ?GEOHASH stores storeA storeB

5. GEOPOS:獲取一個或多個位置的經(jīng)緯度坐標
? ?GEOPOS命令用于獲取一個或多個位置的經(jīng)緯度坐標。


? ?GEOPOS key member [member ...]

? ?示例:

? ?GEOPOS stores storeA storeB
? ?

6. GEORADIUSBYMEMBER:根據(jù)成員獲取范圍內(nèi)的元素
? ?這個命令與GEORADIUS類似,但是它以一個已有的成員作為中心點進行查詢。

?
? ?GEORADIUSBYMEMBER key member radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key]
? 
? ?示例:
? ?
? ?GEORADIUSBYMEMBER stores storeA 1 km
? ?

地理位置功能不僅在查詢附近商戶等實際應用中非常有用,還可以應用于地理分析、位置推薦等領域。它通過利用Redis強大的有序集合數(shù)據(jù)結(jié)構(gòu),使得處理地理信息變得高效、靈活,并且易于集成到現(xiàn)有的應用中。無論是構(gòu)建LBS應用還是處理位置相關數(shù)據(jù),Redis的地理位置功能都能為開發(fā)者提供強大的支持。

Java代碼實現(xiàn)

將數(shù)據(jù)庫中的商家經(jīng)緯度存入redis

數(shù)據(jù)庫中有一張商家表,其中有經(jīng)度,緯度這兩個字段。我們可以通過單元測試批量將這些商家的經(jīng)緯度數(shù)據(jù)存入redis。key為商家id,value為經(jīng)緯度。

/**
     * 將數(shù)據(jù)庫中的商戶坐標添加到緩存
     */
    @Test
    void addShopGeo2Redis(){
        //獲取商戶集合
        List<Shop> list = shopService.list();
        //根據(jù)商戶類型分類
        Map<Long, List<Shop>> collect = list.stream().collect(Collectors.groupingBy(Shop::getTypeId));
        for (Map.Entry<Long, List<Shop>> longListEntry : collect.entrySet()) {
            Long typeId = longListEntry.getKey();
            String key = "shop:geo:" + typeId;
            //獲取商戶經(jīng)緯度
            List<Shop> shopList = longListEntry.getValue();
            List<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>(shopList.size());
            for (Shop shop : shopList) {
//                stringRedisTemplate.opsForGeo().add(key,new Point(shop.getX(),shop.getY()),shop.getId().toString());
                //先收集完所有商戶的地理位置,再一次性添加到redis
                locations.add(new RedisGeoCommands.GeoLocation<>(shop.getId().toString(),new Point(shop.getX(),shop.getY())));
            }
            stringRedisTemplate.opsForGeo().add(key,locations);
        }
    }

接口類:queryShopByType(typeId,current,x,y)

定義一個根據(jù)商家類型查詢所有商家的接口,如果前端傳來的參數(shù)中攜帶該用戶的經(jīng)緯度,則代表需要根據(jù)距離查詢附近商家。

  /**
     * 根據(jù)商鋪類型分頁查詢商鋪信息
     * @param typeId 商鋪類型
     * @param current 頁碼
     * @return 商鋪列表
     */
    @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);
    }

服務類:queryShopByType(typeId,current,x,y)

1.首先判斷是否經(jīng)緯度參數(shù)x和y是否為空

2.計算分頁參數(shù)(redis無法分頁,需要手動分頁)

3.查詢redis

4.獲取商戶id集合

5.根據(jù)商戶id查詢數(shù)據(jù)庫

6.返回

  @Override
    public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
        //1.判斷是否需要根據(jù)坐標查詢
        if(x == null || y == null){
            //直接數(shù)據(jù)庫查詢
            Page<Shop> page = query().eq("type_id", typeId).page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));
            return Result.ok(page.getRecords());
        }
        //2.計算分頁參數(shù)
        int from = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;
        int end = current * SystemConstants.DEFAULT_PAGE_SIZE;

        //3.查詢redis,按照距離排序,分頁。結(jié)果:shopId,distance
        String key = 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>>> list = results.getContent();
        if(list.size() <= from){
            //沒有下一頁
            return Result.ok(Collections.emptyList());
        }
        //4.1截取from——end部分
        List<Long> ids = new ArrayList<>(list.size());
        Map<String, Distance> distanceMap = new HashMap<>(list.size());
        list.stream().skip(from).forEach(result -> {
            String shopIdStr = result.getContent().getName();
            ids.add(Long.valueOf(shopIdStr));
            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();
        for (Shop shop : shops){
            shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());
        }

        //6.返回
        return Result.ok(shops);
    }
}

注意點

1.redis查詢的結(jié)果是從第1條到第end條,不能直接返回第begin條到第end條。

那么如何跳過begin前面的記錄呢?

可以使用stream()流的skip()方法,skip()方法中指定參數(shù)begin,就會跳過前面的begin條記錄。

2.通過redis獲取的ids集合,再使用mybatis-plus使用query().in()進行查詢時,會破壞數(shù)據(jù)順序,如何解決?

手動指定順序。在后面加上last("ORDER BY FIELD(id," + idStr + ")").list()。而idStr = StrUtil.join(",",ids);文章來源地址http://www.zghlxwxcb.cn/news/detail-658299.html

到了這里,關于如何使用Redis實現(xiàn)附近商家查詢的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Redis--Geo指令的語法和使用場景舉例(附近的人功能)

    Redis--Geo指令的語法和使用場景舉例(附近的人功能)

    前言 Redis除了常見的五種數(shù)據(jù)類型之外,其實還有一些少見的數(shù)據(jù)結(jié)構(gòu),如Geo,HyperLogLog等。雖然它們少見,但是作用卻不容小覷。本文將介紹Geo指令的語法和使用場景。 Geo介紹 Geo是\\\"geolocation\\\"的縮寫,即地理定位器,顧名思義就是記錄地理位置信息,用來進行地址位置排序

    2024年01月20日
    瀏覽(35)
  • Redis - 附近商鋪、用戶簽到、UV統(tǒng)計

    Redis - 附近商鋪、用戶簽到、UV統(tǒng)計

    底層都是基于地理坐標進行搜索,支持地理坐標的技術有很多,Redis就是其中之一 GEO 就是Geolocation的簡寫形式,代表 地理坐標 。 Redis 在3.2版本中加入了對GEO的支持, 允許存儲地理坐標信息 ,幫助我們根據(jù)經(jīng)緯度來檢索數(shù)據(jù)。 常見的命令有 : GEOADD :添加一個地理空間信息,

    2024年02月13日
    瀏覽(21)
  • 使用Nodejs搭建HTTP服務,并實現(xiàn)公網(wǎng)遠程訪問Redis數(shù)據(jù)庫「內(nèi)網(wǎng)穿透」

    使用Nodejs搭建HTTP服務,并實現(xiàn)公網(wǎng)遠程訪問Redis數(shù)據(jù)庫「內(nèi)網(wǎng)穿透」

    轉(zhuǎn)載自cpolar極點云文章:公網(wǎng)遠程連接Redis數(shù)據(jù)庫「內(nèi)網(wǎng)穿透」 Redis作為一款高速緩存的key value鍵值對的數(shù)據(jù)庫,在許許多多的場景中廣泛使用,由于是把數(shù)據(jù)存儲在內(nèi)存中,所以讀寫效率極高。 下面介紹如何在內(nèi)網(wǎng)虛擬機的linux中搭建redis并通過cpolar內(nèi)網(wǎng)穿透實現(xiàn)公網(wǎng)訪問 進入

    2024年02月13日
    瀏覽(25)
  • 如何使用 Redis 快速實現(xiàn)分布式鎖?

    如何使用 Redis 快速實現(xiàn)分布式鎖?

    本文我們來討論如何使用 Redis 快速實現(xiàn)分布式鎖。 分布式鎖有很多種解決方案,前面簡單介紹過,Redis 可以通過 set key 方式來實現(xiàn)分布式鎖,但實際情況要更加復雜,比如如何確保臨界資源的串行執(zhí)行,如何及時釋放,都是需要額外考慮的。 本文要講的是一個完備的分布式

    2024年02月04日
    瀏覽(22)
  • 在Spring中,可以使用不同的方式來實現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫、Redis、ZooKeeper等

    在Spring中,可以使用不同的方式來實現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫、Redis、ZooKeeper等

    在Spring中,可以使用不同的方式來實現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫、Redis、ZooKeeper等。下面是兩種常見的實現(xiàn)方式: 使用Redis實現(xiàn)分布式鎖: 使用自定義注解實現(xiàn)本地鎖: 以上是兩種常見的在Spring中實現(xiàn)分布式鎖的方式。第一種方式使用Redis作為分布式鎖的存儲介質(zhì),通過

    2024年03月17日
    瀏覽(24)
  • 126、高頻Redis面試題:如何保證Redis和數(shù)據(jù)庫數(shù)據(jù)一致性

    126、高頻Redis面試題:如何保證Redis和數(shù)據(jù)庫數(shù)據(jù)一致性

    問題:如果數(shù)據(jù)庫中的某條數(shù)據(jù)放入緩存后,又馬上被更新了,那我們應該如何更新緩存 缺點: 如果先更新緩存成功,在更新數(shù)據(jù)庫的時候失敗,這時候會導致數(shù)據(jù)不一致;緩存的作用是不是臨時將我們數(shù)據(jù)保存在內(nèi)存,便于提高查詢速度;但是如果某條數(shù)據(jù)在數(shù)據(jù)庫中都

    2024年02月13日
    瀏覽(27)
  • redis的緩存更新策略以及如何保證redis與數(shù)據(jù)庫的數(shù)據(jù)一致性

    redis的緩存更新策略有這么幾種: 1、由應用直接和redis以及數(shù)據(jù)庫相連接: ?? ??? ?查詢數(shù)據(jù)時,應用去redis中查詢,查不到的話再由應用去數(shù)據(jù)庫中查詢,并將查詢結(jié)果放在redis; ?? ??? ?更新數(shù)據(jù)時,由應用去觸發(fā)redis數(shù)據(jù)的刪除以及數(shù)據(jù)庫的update。 2、應用只跟redi

    2024年02月13日
    瀏覽(25)
  • Redis如何保證緩存和數(shù)據(jù)庫一致性?

    現(xiàn)在我們在面向增刪改查開發(fā)時,數(shù)據(jù)庫數(shù)據(jù)量大時或者對響應要求較快,我們就需要用到Redis來拿取數(shù)據(jù)。 Redis:是一種高性能的內(nèi)存數(shù)據(jù)庫,它將數(shù)據(jù)以鍵值對的形式存儲在內(nèi)存中,具有讀寫速度快、支持多種數(shù)據(jù)類型、原子性操作、豐富的特性等優(yōu)勢。 優(yōu)勢: 性能極高

    2024年01月16日
    瀏覽(40)
  • Redis---數(shù)據(jù)庫和緩存如何保證一致性?

    用「讀 + 寫」請求的并發(fā)的場景來分析: 假如某個用戶數(shù)據(jù)在緩存中不存在,請求 A 讀取數(shù)據(jù)時從數(shù)據(jù)庫中查詢到年齡為 20,在未寫入緩存中時另一個請求 B 更新數(shù)據(jù)。它更新數(shù)據(jù)庫中的年齡為 21,并且清空緩存。這時請求 A 把從數(shù)據(jù)庫中讀到的年齡為 20 的數(shù)據(jù)寫入到緩存

    2024年01月24日
    瀏覽(27)
  • mysql和redis如何保證數(shù)據(jù)庫一致性

    如果對于小公司的單機服務器來說在更新和刪除mysql數(shù)據(jù)的同時對redis緩存進行更新或者刪除就行,一般有兩個選擇,例如: 先更新MySQL,后刪除(或更新)Redis 先刪除(或更新)Redis,后更新MySQL 但是不管使用其中哪種方式,都存在兩個可能的問題: 由于第一步與第二步并不是原

    2023年04月24日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包