黑马点评-附近商户实现
GEO数据结构
Redis在3.2版本中加入了对GEO的支持,允许存储地理坐标信息,根据经纬度来检索数据。
GEO本质上是基于sortedSet实现的,在Sorted Set中,每个成员都是与一个分数(score)相关联的,这个分数用于对成员进行排序。然而,在GEO数据结构中,Redis内部使用一个叫geohash
的算法将每个地理位置的经纬度转换为一个64位的整数,这个整数在Sorted Set中被用作分数(score)。用户在使用GEO相关命令进行操作时,通常不需要直接处理这个分数。
以下为应用场景:
-
附近的人/地点查询: GEO数据结构可以用来实现“附近的人”或“附近的地点”等功能。比如,社交应用可以利用它来查找附近的用户,餐饮服务应用可以用它来显示用户附近的餐馆或咖啡厅。
-
地理位置距离计算: 可以使用GEO数据结构来计算两个地理位置之间的距离,支持不同的单位(米、千米、英里和英尺)。这对于需要展示用户和某个地点之间距离的应用非常有用。
-
地理位置信息检索: 应用程序可以利用GEO数据结构存储地点的地理位置信息,并快速检索。例如,旅游应用可以存储景点的位置信息,用户可以查询特定区域内的所有景点。
-
基于位置的服务(LBS): GEO数据结构支持构建各种基于位置的服务,如配送服务应用可以使用它来计算配送路线和距离,从而优化配送效率和成本。
-
地理围栏(Geofencing): 虽然Redis的GEO数据结构本身不直接支持地理围栏功能,但可以通过与其他功能结合使用来实现。地理围栏允许应用程序在用户进入或离开特定地理区域时触发特定的动作或通知,广泛应用于安全监控、资产跟踪、个性化营销等领域。
-
路线规划与导航: 通过结合GEO数据结构和其他算法,可以实现简单的路线规划和导航功能,帮助用户找到从一个地点到另一个地点的最佳路径。
导入店铺数据到GEO
当我们点击美食之后,会出现一系列的商家,商家中可以按照多种排序方式,我们此时关注的是距离,这个地方就需要使用到我们的GEO,向后台传入当前app收集的地址(我们此处是写死的) ,以当前坐标作为圆心,同时绑定相同的店家类型type,以及分页信息,把这几个条件传入后台,后台查询出对应的数据再返回。
Redis中GEO内部结构:
接下来将数据库表中的数据导入到redis中去,redis中的GEO,GEO在redis中就一个menber和一个经纬度,我们把x和y轴传入到redis做的经纬度位置去,但我们不能把所有的数据都放入到menber中去,毕竟作为redis是一个内存级数据库,如果存海量数据,redis还是力不从心,所以我们在这个地方存储他的id即可。但是这个时候还有一个问题,就是在redis中并没有存储type,所以我们无法根据type来对数据进行筛选,所以我们可以按照商户类型做分组,类型相同的商户作为同一组,以typeId为key存入同一个GEO集合中即可。
void loadShopData() {// 1.查询店铺信息List<Shop> list = shopService.list();// 2.把店铺分组,按照typeId分组,typeId一致的放到一个集合Map<Long, List<Shop>> map = list.stream().collect(Collectors.groupingBy(Shop::getTypeId));// 3.分批完成写入Redisfor (Map.Entry<Long, List<Shop>> entry : map.entrySet()) {// 3.1.获取类型idLong 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 经度 纬度 memberfor (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);}
}
实现附近商户功能
接口:
@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);
}
逻辑实现:
@Overridepublic 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、distanceString 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.解析出idif (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.获取店铺idString shopIdStr = result.getContent().getName();ids.add(Long.valueOf(shopIdStr));// 4.3.获取距离Distance distance = result.getDistance();distanceMap.put(shopIdStr, distance);});// 5.根据id查询ShopString 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);}
相关文章:

黑马点评-附近商户实现
GEO数据结构 Redis在3.2版本中加入了对GEO的支持,允许存储地理坐标信息,根据经纬度来检索数据。 GEO本质上是基于sortedSet实现的,在Sorted Set中,每个成员都是与一个分数(score)相关联的,这个分数用于对成员进行排序…...

安装nginx:手动安装和yum安装
本文在centos7.9下分别尝试了yum安装和手动安装,记录一下试验过程。为后来者少踩点坑。 下载 下载地址:链接 。建议下载稳定版本,也就是Stable Version,这里下载的是 nginx-1.24.0 # 我下载在如下文件夹 mkdir/opt/apps cd /op…...

【C++ STL详解】——string类
目录 前言 一、string类对象的常见构造 二、string类对象的访问及遍历 1.下标【】(底层operator【】函数) 编辑 2.迭代器 3.范围for 4.at 5.back和front 三、string类对象的容量操作 1.size 和 length 2.capacity 3.empty 4.clear 5.res…...

MatplotlibPython 1 3.7
放大数据,如果想仔细看某一行的数据的时候 可以调不同的颜色,图片的长宽高,以及线的种类 plt.figure 这个命令下的所有东西都在这个figure里面 plt.xlim 改变坐标轴的范围 plt.xlabel 改变坐标轴的总名称 plt.xticks 换单位 plt.yt…...
深入理解 Dubbo:构建分布式服务治理体系
目录 1. 介绍 2. Dubbo 的核心概念 2.1 服务提供者(Provider)与服务消费者(Consumer) 2.2 注册中心(Registry) 2.3 监控中心(Monitor) 3. Dubbo 的功能特性 3.1 远程调用&…...
唤起原生IOS和安卓Android app的方法
大家好我是咕噜美乐蒂,很高兴又和大家见面了! 要唤起原生 iOS 或 Android 应用程序,你可以使用以下方法: 唤起原生 iOS 应用程序 在 iOS 上,你可以使用自定义 URL 方案或 Universal Links 来唤起原生应用程序。以下…...

RabbitMQ的web控制端介绍
2.1 web管理界面介绍 connections:无论生产者还是消费者,都需要与RabbitMQ建立连接后才可以完成消息的生产和消费,在这里可以查看连接情况channels:通道,建立连接后,会形成通道,消息的投递、获取…...

GitHub登不上:修改hosts文件来解决(GitHub520,window)
参考链接:GitHub520: 本项目无需安装任何程序,通过修改本地 hosts 文件,试图解决: GitHub 访问速度慢的问题 GitHub 项目中的图片显示不出的问题 花 5 分钟时间,让你"爱"上 GitHub。 (gitee.com) GitHub网站…...

01-DevOps代码上线-git入门及gitlab远程仓库
一、准备学习环境 10.0.0.71-gitlab 2c2g-20GB 10.0.0.72-jenkins 2c2g-20GB 10.0.0.73-sonarqube 1c1g-20GB 10.0.0.74-nexus 1c1g-20GB 10.0.0.75-dm 1c1g-20GB (模拟写代码服务器) 在centos系统中&…...

EdgeX Foundry 安全模式安装部署
文章目录 一、安装准备1.官方文档2. 克隆服务器3.安装 Docker4.安装 docker-compose 二、安装部署1.docker-comepse2.启动 EdgeX Foundry3.访问 UI3.1. consul3.2. EdgeX Console EdgeX Foundry # EdgeX Foundryhttps://iothub.org.cn/docs/edgex/ https://iothub.org.cn/docs…...

网络安全-appcms-master
一、环境 gethub上面自己找appcms-master 二、分析一下源码以及闯关思路 首先是有一个函数循环以及函数过滤,我们的post会将我们所传的所有val值去进行一个循环,之后通过htmlspecialchars这个函数进行过滤和转换所以val值不能通过单双引号闭合注入的方…...
ThreadLocal 与 synchronized 区别
我的理解 目的都是为了一个大前提:操作内容的线程安全。 任务不同:synchronized 解决的是多线程下线程操作权限的问题,以及原子性的保证。通过对锁的竞争,达到对资源的访问有序。 ThreadLocal是解决的事多线程下资源的隔离问题,即…...

灵魂指针,教给(二)
欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 C语言知识 先赞后看,已成习惯 创作不易,多多支持! 目录 一、数组名的理解 二、使用指针访问数组 三、一维数组传参本质 四、冒泡排序 五、二级指针 六、指针数组 七、指针数组…...
线程安全--浅谈Ad-hoc与加锁的区别
浅谈Ad-hoc 与加锁 两者要解决的都是对对象的语义混乱操作,即有个count进行累加操作。 我的理解/文心一言的反馈如下: 加锁是保证我们对同一个count在多线程下的访问有序,即“读写-修改-写入”具有原子性。 而Ad-hoc机制就是通过程序员自己定义一个私有…...

数据治理实战——翼支付金融板块业务数仓建设和数据治理之路
目录 一、数据治理背景 二、数据治理建设内容 2.1 组织协同 2.2 平台建设 2.3 数据应用治理 2.4 数据规范 2.5 数据安全 三、企业级数仓建设 3.1 调研阶段 2.2 平台护航 2.3 数仓分层 2.4 维度建模 2.4.1 维度建模四步曲 2.4.2 命名规范 2.4.3 资产沉淀 2.4.4 …...

[Buuctf] [MRCTF2020]Transform
1.查壳 64位exe文件,没有壳 2.用64位IDA打开 找到主函数,F5查看伪代码 从后往前看,有一个判断语句,是两个数组进行比较的,我们双击byte_40F0E0查看里面的内容 所以能够推出byte_414040的内容,byte_4140…...

【C++】C++模板基础知识篇
个人主页 : zxctscl 文章封面来自:艺术家–贤海林 如有转载请先通知 文章目录 1. 泛型编程2. 函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 3. 类模板3.1 类模板的定义格式3.2 类模板的实例化…...

golang 注释插件
Goanno插件 自动生成golang注释,该插件为 Intellij/Goland 中的 golang 提供自动生成注释 如何使用? control command / (for windows: control alt /)(生成注释)Right click -> Generate -> Goanno(生成注释&#x…...

Unity插件之天气系统UniStorm
首先呢,它是一款强大的动态昼夜天气系统,能够以较快的帧速率创建AAA级动态生成的天气、照明和天空,并且具有300多个可定制的组件,允许用户创建任何可以想象的环境。 第一步:他需要两个物体Camera摄像机、Player播放器…...
Java使用xlsx-streamer和EasyExcel解决读取超大excel文件数据处理方法
前言 最近有个项目在生产环境做数据导入时,发现开始执行导入任务会出现cpu狂飙的情况。几番定位查找发现是在读取excel的时候导致此问题的发生,因此在通常使用的为POI的普通读取,在遇到大数据量excel,50MB大小或数五十万行的级别的…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...