Redis实现附近商户

news2024/11/15 4:57:06

GEO数据结构的基本用法

GEO就是Geolocation的简写形式,代表地理坐标。Redis在3.2版本中加入了对GEO的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。常见的命令有:

  • GEOADD:添加一个地理空间信息,包含:经度(longitude)、纬度(latitude)、值(member)
  • GEODIST:计算指定的两个点之间的距离并返回
  • GEOHASH:将指定member的坐标转为hash字符串形式并返回
  • GEOPOS:返回指定member的坐标
  • GEORADIUS:指定圆心、半径,找到该圆内包含的所有member,并按照与圆心之间的距离排序后返回。6.以后已废弃
  • GEOSEARCH:在指定范围内搜索member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。6.2.新功能
  • GEOSEARCHSTORE:与GEOSEARCH功能一致,不过可以把结果存储到一个指定的key。 6.2.新功能

导入店铺数据到GEO  

当我们点击美食之后,会出现一系列的商家,商家中可以按照多种排序方式,我们此时关注的是距离,这个地方就需要使用到我们的GEO,向后台传入当前app收集的地址(我们此处是写死的) ,以当前坐标作为圆心,同时绑定相同的店家类型type,以及分页信息,把这几个条件传入后台,后台查询出对应的数据再返回。

我们要做的事情是:将数据库表中的数据导入到redis中去,redis中的GEO,GEO在redis中就一个menber和一个经纬度,我们把x和y轴传入到redis做的经纬度位置去,但我们不能把所有的数据都放入到menber中去,毕竟作为redis是一个内存级数据库,如果存海量数据,redis还是力不从心,所以我们在这个地方存储他的id即可。

但是这个时候还有一个问题,就是在redis中并没有存储type,所以我们无法根据type来对数据进行筛选,所以我们可以按照商户类型做分组,类型相同的商户作为同一组,以typeId为key存入同一个GEO集合中即可

@Test
void loadShopData() {
    // 1.查询店铺信息
    List<Shop> list = shopService.list();
    // 2.把店铺分组,按照typeId分组,typeId一致的放到一个集合
    Map<Long, List<Shop>> map = list.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 = 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 经度 纬度 member
        for (Shop shop : value) {
            // stringRedisTemplate.opsForGeo().add(key, new Point(shop.getX(), shop.getY()), shop.getId().toString());
            locations.add(new RedisGeoCommands.GeoLocation<>(
                    shop.getId().toString(),
                    new Point(shop.getX(), shop.getY())
            ));
        }
        stringRedisTemplate.opsForGeo().add(key, locations);
    }
}

实现附近商户功能

SpringDataRedis的2.3.9版本并不支持Redis 6.2提供的GEOSEARCH命令,因此我们需要提示其版本,修改自己的POM

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>spring-data-redis</artifactId>
            <groupId>org.springframework.data</groupId>
        </exclusion>
        <exclusion>
            <artifactId>lettuce-core</artifactId>
            <groupId>io.lettuce</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.6.2</version>
</dependency>
<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.1.6.RELEASE</version>
</dependency>

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);
}

ShopServiceImpl

@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、按照距离排序、分页。结果:shopId、distance
        String key = SHOP_GEO_KEY + typeId;
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo() // GEOSEARCH key BYLONLAT x y BYRADIUS 10 WITHDISTANCE
                .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 -> {
            // 4.2.获取店铺id
            String shopIdStr = result.getContent().getName();
            ids.add(Long.valueOf(shopIdStr));
            // 4.3.获取距离
            Distance distance = result.getDistance();
            distanceMap.put(shopIdStr, distance);
        });
        // 5.根据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);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1111136.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【广州华锐互动】VR石油钻井井控实训系统

在过去的几十年中&#xff0c;石油工业的发展速度一直在加快。为了适应这个快速发展的行业&#xff0c;需要新的技术和工具&#xff0c;而VR&#xff08;虚拟现实&#xff09;技术正是其中之一。本文将探讨VR石油钻井井控实训系统在石油工业教育中的应用。 在真实的钻井环境中&…

接口管理神器Apipost

自诞生以来&#xff0c;Apipost凭借其简洁直观的用户界面、强大的功能以及简单、易上手的操作&#xff0c;让Apipost成为了开发人员不可或缺的工具。本文将详细介绍Apipost的主要功能和使用方法&#xff0c;帮助大家更好地了解这款优秀的API开发工具。 下载安装 直接进入Apip…

Stable Diffusion WebUI扩展a1111-sd-webui-tagcomplete之Booru风格Tag自动补全功能详细介绍

安装地址 直接附上地址先: Ranting8323 / A1111 Sd Webui Tagcomplete GitCodeGitCode——开源代码托管平台,独立第三方开源社区,Git/Github/Gitlabhttps://gitcode.net/ranting8323/a1111-sd-webui-tagcomplete.git上面是GitCode的地址,下面是GitHub的地址,根据自身情…

个人微信CRM客户管理系统怎么选?功能介绍

现在市面上有许多种类的个人微信CRM客户管理系统可供选择&#xff0c;因此&#xff0c;我们需要选择最适合自己需求的微信管理系统CRM&#xff0c;最重要的是根据您的需求和期望的功能来进行筛选。 如何选择适合自己的微信CRM客户管理系统&#xff1f; 现在市面上的系统五花八…

Cloud Studio连接MySQL,Access denied for一系列问题

官方文档有写如何安装Mysql $ apt update $ apt install mysql-server mysql-client -y$ service mysql start mysql -uroot -p123456进入MySQL命令行 问题出在连接数据库这一步&#xff0c;命令行能进去&#xff0c;但是数据库插件和代码都连不上 Access denied for 大概率…

基于SSM的外卖点餐系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue、HTML 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是…

python实现列表倒叙打印

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 def func(listNode):listNode.reverse()for i in listNode:print(i)li [1,2,3,4,5] func(li)利用python列表函数reverse&#xff08;&#xff09;将列表倒叙&#xff0c;然后遍历打印&#xff0c;但是这有一个缺点就是改变了…

固态硬盘的日常注意事项

固态硬盘是一种高速、低功耗、无噪音、抗震动的存储设备&#xff0c;但是在使用过程中也需要注意以下几点&#xff1a; 避免频繁重复写入同一块区域&#xff0c;这会缩短固态硬盘的使用寿命。定期清理垃圾文件和临时文件&#xff0c;以免占用过多的存储空间。避免在固态硬盘上…

RISC-V架构——物理内存属性和物理内存保护

1、物理内存属性&#xff08;PMA&#xff1a;Physical Memory Attributes&#xff09; &#xff08;1&#xff09;系统内存映射包含各种不同属性的地址空间范围&#xff0c;每个地址空间范围支持的操作不一样&#xff1b; &#xff08;2&#xff09;物理内存属性一般是在芯片设…

使用IDEA2022.1创建Maven工程出现卡死问题

使用IDEA创建Maven工程出现卡死问题&#xff0c;这个是一个bug 这里是别人和官方提供这个bug,大家可以参考一下 话不多说&#xff0c;上教程 解决方案&#xff1a; 方案1&#xff1a;更新idea版本 方案2&#xff1a;关闭工程&#xff0c;再新建&#xff0c;看图

开源设计和原型平台 Penpot:跨领域团队的愉快体验 | 开源日报 No.59

penpot/penpot Stars: 23.8k License: MPL-2.0 Penpot 是第一个面向跨领域团队的开源设计和原型平台。它不依赖于操作系统&#xff0c;基于 Web&#xff0c;并使用开放标准 (SVG)。 为跨领域团队而生&#xff1a;专注于设计和代码团队&#xff0c;提供无需频繁交接工作的愉快…

数字图像处理实验记录三(双线性插值和最邻近插值)

前言&#xff1a;个人实验记录&#xff0c;仅供学习参考&#xff0c;实验报告别用我图 文章目录 一、基础知识1&#xff0c;为什么要进行插值&#xff1a;2&#xff0c;双线性插值原理&#xff1a;3&#xff0c;最邻近插值&#xff1a; 二、实验要求&#xff1a;1&#xff0e;…

215. 破译密码 - mobius函数 + 整数分块

215. 破译密码 - AcWing题库 mobius函数&#xff1a; 一个数的分解质因数形式&#xff0c;某一个指数>1为0&#xff0c;质因数为奇数个为-1&#xff0c;偶数个为1 mobius函数可以与容斥结合起来&#xff0c;比如mobius[2] -1, mobius[3] -1, mobius[2 * 3] 1。对应容斥…

硬件系统工程师宝典(44)-----差分信号走线“相位失配”怎么破?

各位同学大家好&#xff0c;欢迎继续做客电子工程学习圈&#xff0c;今天我们继续来讲这本书&#xff0c;硬件系统工程师宝典。 上篇我们说到了PCB在布局时除了要满足结构需求&#xff0c;还要考虑模块划分、特殊器件的布局以及散热问题。今天来说说高速PCB布线的一些注意事项…

2023服务端测试开发必备技能:Mock测试

什么是mock测试 Mock 测试就是在测试活动中&#xff0c;对于某些不容易构造或者不容易获取的数据/场景&#xff0c;用一个Mock对象来创建以便测试的测试方法。 Mock测试常见场景 无法控制第三方系统接口的返回&#xff0c;返回的数据不满足要求依赖的接口还未开发完成&#…

【Docker】Docker里面安装win系统

前端时间还早想着在win上面安装DokerDesktop&#xff0c;处理暂用【Docker】Docker Desktop更换非C盘符(减轻占用率)&#xff0c;这次心想可否反过来呢&#xff1f;就是想在&#xff1a;Docker里面安装win系统 docker pull microsoft/windowsservercoredocker create --name …

Apriori(关联规则挖掘算法)

关联规则分析 事务库 上表所示的购物篮数据即是一个事务库&#xff0c;该事务库记录的是用户行为的数据。 事务 上表事务库中的每一条记录被称为一笔事务。在购物篮事务中&#xff0c;每一次购物行为即为一笔事务&#xff0c;例如第一行数据“用户1购买商品A,B,C”即为一条事…

【MATLAB源码-第51期】基于matlab的粒子群算法(PSO)的栅格地图路径规划。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;是一种模拟鸟群觅食行为的启发式优化方法。以下是其详细描述&#xff1a; 基本思想&#xff1a; 鸟群在寻找食物时&#xff0c;每只鸟都会…

完美解决 在将最终稿件上传到 IEEE PDF eXpress进行格式检查是出现“font not embedded“的问题 (不会出现自动压缩图像的现象)

最近中了一篇IEEE的论文&#xff0c;在校稿阶段&#xff0c;final paper是需要通过IEEE PDF eXpress网站的格式检查&#xff0c;然后出现一下问题&#xff1a; Errors: Font TimesNewRomanPS-BoldMT, TimesNewRomanPS-ItalicMT, TimesNewRomanPSMT is not embedded 用人话说就…

贝锐花生壳+Fooocus,快速自建可远程访问的SDXL,平替Midjourney

Midjourney、stable diffusion两款AI绘图工具是最近这段时间的热点。不过&#xff0c;事无完美&#xff0c;他们各有一些优缺点。 例如&#xff1a;stable diffusion虽然开源可私有化部署&#xff0c;但操作相对复杂&#xff0c;需要设置各类参数&#xff1b;Midjourney虽然简单…