Redis实战案例25-附近商铺功能

news2024/11/24 18:47:57

1. GEO数据结构

Redis中Geohash功能应用
在这里插入图片描述
在这里插入图片描述

添加地理坐标

在这里插入图片描述
在这里插入图片描述

求两点之间距离

在这里插入图片描述

搜索天安门附近10km的火车站,按升序

在这里插入图片描述

2. 导入店铺数据到GEO

在这里插入图片描述

Redis中存储店铺的信息,将店铺的id和经纬度坐标存到GEO数据类型中去,其中member存id,经纬度对应x和y;
存储对应店铺信息之后,才能去计算对应的距离排序,之后得出附近店铺功能时,得到就是id,根据id查询店铺即可;

但是这里存储在GEO中的只有店铺id和地理坐标,并没有类型id,所以要对商铺类型进行分类;
在这里插入图片描述

这里直接写测试进行商户类型分组了,写到Redis中去

/**
 * 进行店铺分组
 */
@Test
void loadShopData(){
    //查询店铺信息
    List<Shop> list = shopService.list();
    //把店铺分组,按照typeId分组,一致的放到一个集合中
    Map<Long, List<Shop>> map = list.stream().collect(Collectors.groupingBy(Shop::getTypeId));
    //分批写入Redis中
    for (Map.Entry<Long, List<Shop>> entry:map.entrySet()) {
        //获取类型id
        Long typeId = entry.getKey();
        String key = SHOP_GEO_KEY + typeId;
        //获取同类型的店铺的集合
        List<Shop> value = entry.getValue();
        ArrayList<RedisGeoCommands.GeoLocation<String>> geoLocations = new ArrayList<RedisGeoCommands.GeoLocation<String>>(value.size());
        //写入Redis GEOADD key 经度 纬度 member
        for (Shop shop:value) {
            //stringRedisTemplate.opsForGeo().add(key, new Point(shop.getX(), shop.getY()), shop.getId().toString());
            geoLocations.add(new RedisGeoCommands.GeoLocation<>(
                    shop.getId().toString(),
                    new Point(shop.getX(),shop.getY())
            ));
        }
        stringRedisTemplate.opsForGeo().add(key, geoLocations);
    }
}

在这里插入图片描述

3. 附近商铺搜索

在这里插入图片描述

x和y参数采用required = false,传了参数则采用GEO方式查,没传参数则采用别的方式查询排序

/**
 * 根据商铺类型分页查询商铺信息
 * @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);
}

有点难,等以后有水平了再来修改吧~

/**
 * 根据商铺类型分页查询商铺信息
 * @param typeId
 * @param current
 * @param x
 * @param y
 * @return
 */
@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().search(
            key,
            GeoReference.fromCoordinate(x, y),
            new Distance(5000),
            //limit是限制范围,但是只能指定结束,都是从第一条开始到结束,只能对结果手动截取
            //默认单位为m,当前为5km,结果也是m
            RedisGeoCommands.GeoRadiusCommandArgs.newGeoSearchArgs().includeCoordinates().limit(end)
    );
    //4.解析出id
    if(results == null){
        return Result.ok(Collections.emptyList());
    }
    //       当前集合从0到end,需要手动截取        list.subList() 或者stream流
    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 -> {
        //参见test测试单元的存储过程
        //获取店铺id
        String shopId = result.getContent().getName();
        //需要把id转换为long类型的进行查询店铺信息
        ids.add(Long.valueOf(shopId));
        //获取距离
        Distance distance = result.getDistance();
        //保证id与distance一一对应
        distanceMap.put(shopId,distance);
    });
    //5.根据id查询店铺
    String idStr = StrUtil.join(",", ids);
    List<Shop> shops = query().in("id", ids)
            .last("ORDER BY FIELD(id," + idStr + ")").list();//        6.返回
    //在实体类,distance是只属于实体类,用于返回给前端的字段
    for (Shop shop : shops) {
        //因为集合有存储,所以根据id来取出值,但是取出的是对象,需要调用getValue来转成相应的值
        shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());
    }
    return Result.ok(shops);
}

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

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

相关文章

关于自动化测试用例失败重试的一些思考

自动化测试用例失败重跑有助于提高自动化用例的稳定性&#xff0c;那我们来看一下&#xff0c;python和java生态里都有哪些具体做法&#xff1f; 怎么做 如果是在python生态里&#xff0c;用pytest做测试驱动&#xff0c;那么可以通过pytest的插件pytest-rerunfailures来实现…

第十三次CCF计算机软件能力认证

第一题&#xff1a;跳一跳 近来&#xff0c;跳一跳这款小游戏风靡全国&#xff0c;受到不少玩家的喜爱。 简化后的跳一跳规则如下&#xff1a;玩家每次从当前方块跳到下一个方块&#xff0c;如果没有跳到下一个方块上则游戏结束。 如果跳到了方块上&#xff0c;但没有跳到方块的…

Python(七十一)集合的概述与创建

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

自然语言处理:长文本场景下的关键词抽取实践

NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型压缩算法等 专栏详细介绍:NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型…

第四章 kernel函数基础篇

cuda教程目录 第一章 指针篇 第二章 CUDA原理篇 第三章 CUDA编译器环境配置篇 第四章 kernel函数基础篇 第五章 kernel索引(index)篇 第六章 kenel矩阵计算实战篇 第七章 kenel实战强化篇 第八章 CUDA内存应用与性能优化篇 第九章 CUDA原子(atomic)实战篇 第十章 CUDA流(strea…

【Python ezdxf+matplotlib】显示AutoCAD导出的.dxf格式文件

代码&#xff1a; import ezdxf,matplotlib import matplotlib.pyplot as plt from matplotlib.patches import Polygon matplotlib.use(TkAgg) # 避免Matplotlib版本与其他相关库的兼容性问题def display_dxf(file_path):doc ezdxf.readfile(file_path)msp doc.modelspac…

Maven命令启动SpringBoot项目

用Maven命令启动SpringBoot项目&#xff0c;记录如下&#xff1a; mvn spring-boot:run C:\Users\Administrator\source\repos\kd-datacenter\server\kd-datacenter>mvn spring-boot:run

HBase-组成

client 读写请求HMaster 管理元数据监控region是否需要进行负载均衡&#xff0c;故障转移和region的拆分RegionServer 负责数据cell的处理&#xff0c;例如写入数据put&#xff0c;查询数据get等 拆分合并Region的实际执行者&#xff0c;由Master监控&#xff0c;由regionServ…

Idea中maven无法下载源码

今天在解决问题的时候想要下载源码&#xff0c;突然发现idea无法下载&#xff0c;这是真的蛋疼&#xff0c;没办法查看原因&#xff0c;最后发现问题的原因居然是因为Maven&#xff0c;由于我使用的idea的内置的Bundle3的Maven&#xff0c;之前没有研究过本地安装和内置的区别&…

MyBatis-动态SQL-foreach

目录 标签有以下常用属性&#xff1a; 小结 <froeach> <foreach>标签有以下常用属性&#xff1a; collection&#xff1a;指定要迭代的集合或数组的参数名&#xff08;遍历的对象&#xff09;。item&#xff1a;指定在迭代过程中的每个元素的别名&#xff08;遍历…

D. Productive Meeting

Example input 8 2 2 3 3 1 2 3 4 1 2 3 4 3 0 0 2 2 6 2 3 0 0 2 5 8 2 0 1 1 5 0 1 0 0 6 output 2 1 2 1 2 3 1 3 2 3 2 3 5 1 3 2 4 2 4 3 4 3 4 0 2 1 2 1 2 0 4 1 2 1 5 1 4 1 2 1 5 2 解析&#xff1a; 贪心&#xff0c;每次选择两个剩余次数最多的人&#xff0c;并…

使用hutool工具生成树形结构

假设要构建一个菜单&#xff0c;可以实现智慧库房&#xff0c;菜单的样子如下&#xff1a; 智慧库房|- RFID|- 智慧大屏|- 智能密集架|- 环境管控那这种结构如何保存在数据库中呢&#xff1f;一般是这样的&#xff1a; ​ 每条数据根据parentId相互关联并表示层级关系&#x…

【应用层】- HTTP协议

目录 HTTP简介 认识URL 协议方案名 登录信息&#xff08;认证&#xff09; 服务器地址 服务器端口号 带层次的文件路径 查询字符串 片段标识符 urlencode和urldecode urlencode编码工具 HTTP协议格式 HTTP请求协议格式 如何将有效载荷跟HTTP报头进行分离&#xff…

应急响应-linux挖矿病毒的实战处置

0x01 服务器现状分析 客户描述服务器卡顿&#xff0c;切通过搜索引擎进去该官网跳转非法页面&#xff0c;但本地访问无异常 0x02 信息收集 通过进程占用情况cpu功率拉满&#xff0c;确定被植入挖矿病毒文件 qq 且存在计划任务update.sh&#xff1a;crontab -l 将该文件上传沙…

RabbitMQ消息队列

目录 网址&#xff1a; 一、项目准备 1.导入依赖 2.抽取工具类 配置的属性在哪里呢 二、代码编写 1.简单模式 生产者 消费者 2.Work queues工作队列模式 生产者 消费者1 消费者2 3.Publish/Subscribe发布与订阅模式 生产者 消费者1 消费者2 4.Routing路由模式…

伦敦金费用有哪几方面?

通常在网上开设伦敦金投资账户是没有成本的&#xff0c;而它交易的费用&#xff0c;主要是由点差和过夜利息&#xff08;仓息&#xff09;构成。如果伦敦金投资者只是做短线的日内交易&#xff0c;做一手完整的100盎司的标准合约&#xff0c;需要支付大约50美元点差费用&#x…

备忘录模式(C++)

定义 在不破坏封装性的前提下&#xff0c;捕获一-个对象的内部状态&#xff0c;并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。 应用场景 ➢在软件构建过程中&#xff0c;某些对象的状态在转换过程中&#xff0c;可能由于某种需要&#xff0c;要…

【vim 学习系列文章 4 - vim与系统剪切板之间的交互】

文章目录 背景1.1.1 vim支持clipboard 检查1.1.2 vim的寄存器 上篇文章&#xff1a;【vim 学习系列文章 3 - vim 选中、删除、复制、修改引号或括号内的内容】 背景 从vim中拷贝些文字去其它地方粘贴&#xff0c;都需要用鼠标选中vim的文字后&#xff0c;Ctrlc、Ctrlv&#x…

回归决策树模拟sin函数

# -*-coding:utf-8-*- import numpy as np from sklearn import tree import matplotlib.pyplot as pltplt.switch_backend("TkAgg") # 创建了一个随机数生成器对象 rng rngnp.random.RandomState(1) print("rng",rng) #5*rng.rand(80,1)生成一个80行、1列…

以公益之行,筑责任之心——2023年中创算力爱心公益助学活动

捐资助学是一项功在当代、利在千秋的义举。 高考录取工作已经开始&#xff0c;一张张高校录取通知书也陆续送达各位准大学生手中。当他们怀揣着对大学的好奇与憧憬&#xff0c;准备迈进理想的大学时&#xff0c;还有一群人&#xff0c;他们渴望知识&#xff0c;却因经济困难而…