基于Redis实现-附近商铺查询

news2025/7/19 0:55:25

基于Redis实现-附近查询

这个功能将使用到Redis中的GEO这种数据结构来实现。

1.GEO相关命令

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

  • GEOADD: 添加一个地理空间信息,包含:经度(longitude)、纬度(latitude)、值(member)

  • GEODIST: 计算指定的两个点之间的距离并返回

  • GEOHASH: 将指定member的坐标转为hash字符串形式并返回

  • GEOPOS: 返回指定member的坐标

  • GEORADIUS: 指定圆心、半径,找到该圆内包含的所有member,并按照与圆心之间的距离排序后返回。6.2以后已废弃

  • GEOSEARCH: 在指定范围内搜索member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。6.2.新功能

  • GEOSEARCHSTORE: 与GEOSEARCH功能一致,不过可以把结果存储到一个指定的key。6.2.新功能

2.使用GEO来实现以下功能

  1. 添加下面几条数据:

    • 北京南站(116.378248 39.865275)
    • 北京站(116.42803 39.903738)
    • 北京西站(116.322287 39.893729)
    # 1. 添加地理空间数据
    GEOADD stations 116.378248 39.865275 "北京南站" 116.42803 39.903738 "北京站" 116.322287 39.893729 "北京西站"
    

    在这里插入图片描述

  2. 计算北京西站到北京站的距离

    # 2. 计算北京西站到北京站的距离
    GEODIST stations "北京西站" "北京站" km
    

    在这里插入图片描述

  3. 搜索天安门(116.397904 39.909005)附近10km内的所有火车站,并按照距离升序排序

    # 3. 搜索天安门附近10km内的火车站并按距离排序
    GEOSEARCH stations FROMLONLAT 116.397904 39.909005 BYRADIUS 10 km ASC
    

    在这里插入图片描述

在这里插入图片描述

3.使用Java实现简单的附近商铺查询

//在ServiceImpl中(简单演示)
@Autowired
    private StringRedisTemplate stringRedisTemplate;
@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中查询附近店铺ID(GEO查询)
    String key = "shop:geo:" + typeId;  // GEO数据存储的key
    
    // 执行GEO搜索:以(x,y)为中心,5000米半径范围内,查询end数量的店铺
    GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo().search(
            key,
            GeoReference.fromCoordinate(x, y),  // 中心点坐标
            new Distance(5000),                // 搜索半径(5公里)
            RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs()
                    .includeDistance()         // 包含距离信息
                    .limit(end)                // 限制返回数量
    );

    // 4. 处理查询结果并获取店铺详情
    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());  // 结果不足时分页返回空
    }

    // 收集店铺ID和距离信息
    List<Long> ids = new ArrayList<>(list.size());
    Map<String, Distance> distanceMap = new HashMap<>(list.size());
    
    // 跳过前from条记录(分页处理),然后处理剩余记录
    list.stream().skip(from).forEach(result -> {
        String id = result.getContent().getName();  // 获取店铺ID
        ids.add(Long.valueOf(id));
        distanceMap.put(id, result.getDistance()); // 存储店铺距离
    });

    // 根据ID批量查询店铺详情(保持ID顺序)
    String strIds = StrUtil.join(",", ids);
    List<Shop> shops = query()
            .in("id", ids)  // 按ID列表查询
            .last("ORDER BY FIELD(id," + strIds + ")")  // 保持Redis返回的顺序
            .list();

    // 为每个店铺设置距离信息
    for (Shop shop : shops) {
        shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());
    }

    // 5. 返回带距离信息的店铺列表
    return Result.ok(shops);
}

4.Redis GEO search 方法的参数

  1. 排序方式
.sortAscending()    // 按距离升序排序(从近到远)
.sortDescending()  // 按距离降序排序(从远到近)
  1. 返回内容控制
.includeDistance()  // 在结果中包含距离信息
.includeCoordinates() // 在结果中包含坐标信息
.includeName()     // 在结果中包含成员名称(默认包含)
  1. 结果限制
.limit(50)         // 限制返回结果数量(可用于简单分页)
  1. 单位设置
.includeDistance().withDistance(Metrics.KILOMETERS) // 指定距离单位
//支持的单位:
//Metrics.KILOMETERS(千米)
//Metrics.MILES(英里)
//Metrics.FEET(英尺)
//Metrics.METERS(米)
  1. GeoReference 的三种主要形式
//1.fromCoordinate(x, y)
//作用:通过经纬度坐标指定中心点
//示例:
GeoReference.fromCoordinate(116.404, 39.915)  // 北京天安门坐标

//2.fromMember(memberName)
//作用:通过 Redis中已存储的GEO成员名称指定中心点
//示例:
GeoReference.fromMember("北京站")  // 以已存储的"北京站"坐标为中心

//3.fromString("x,y")
//作用:通过字符串格式的坐标指定中心点
//示例:
GeoReference.fromString("116.404,39.915")

如下为完整示例:

GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo().search(
    "shop:geo:1",
    GeoReference.fromCoordinate(116.397904, 39.909005),
    new Distance(5, Metrics.KILOMETERS),
    RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs()
        .includeDistance()      // 包含距离
        .includeCoordinates()   // 包含坐标
        .sortAscending()        // 按距离升序
        .limit(100)             // 最多返回100条
        .withDistance(Metrics.KILOMETERS) // 距离单位为千米
);

对于 Redis 6.2 及以上版本,还可以使用:

  1. 矩形范围搜索
.byBox(width, height, Metrics.KILOMETERS) // 矩形范围搜索
  1. 存储搜索结果
.store("result-key")  // 将结果存储到指定key
.storeDist("result-key") // 存储带距离的结果

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

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

相关文章

【java WEB】恢复补充说明

Server 出现javax.servlet.http.HttpServlet", according to the project’s Dynamic Web Module facet version (3.0), was not found on the Java Build Path. 右键项目 > Properties > Project Facets。Dynamic Web Module facet version选4.0即可 还需要在serv…

安川机器人常见故障报警及解决办法

机器人权限设置 操作权限设置(如果密码不对,就证明密码被人修改) 编辑模式密码:无(一把钥匙,默认) 管理模式密码:999999999(9个9,二把钥匙) 安全模式密码:555555555(9个5,三把钥匙,权限最高,有的型号机器人,没有此模式,但最高密码为安全模式密码) 示教器…

tiktok web X-Bogus X-Gnarly 分析

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向过程 部分python代码 import req…

kes监控组件安装

环境准备 创建监控用户 useradd -m -s /bin/bash -d /home/kmonitor kmonitor passwd k_monitor usermod –a –G kingbase kmonitor 检查java版本 java –version [kmonitorkingbase node_exporter]$ java -version java version "1.8.0_341" Java(TM) SE …

React-Native Android 多行被截断

1. 问题描述&#xff1a; 如图所示&#xff1a; 2. 问题解决灵感&#xff1a; 使用相同的react-native代码&#xff0c;运行在两个APP&#xff08;demo 和 project&#xff09;上。demo 展示正常&#xff0c;project 展示不正常。 对两个页面截图&#xff0c;对比如下。 得出…

深度学习【Logistic回归模型】

回归和分类 回归问题得到的结果都是连续的&#xff0c;比如通过学习时间预测成绩 分类问题是将数据分成几类&#xff0c;比如根据邮件信息将邮件分成垃圾邮件和有效邮件两类。 相比于基础的线性回归其实就是增加了一个sigmod函数。 代码 import matplotlib.pyplot as plt i…

数据科学与计算

1.设计目标与安装 Seaborn 是一个建立在 Matplotlib 基础之上的 Python 数据可视化库&#xff0c;专注于绘制各种统计图形&#xff0c;以便更轻松地呈现和理解数据。Seaborn 的设计目标是简化统计数据可视化的过程&#xff0c;提供高级接口和美观的默认主题&#xff0c;使得用…

怎样给MP3音频重命名?是时候管理下电脑中的音频文件名了

在处理大量音频文件时&#xff0c;给这些文件起一个有意义的名字可以帮助我们更高效地管理和查找所需的内容。通过使用专业的文件重命名工具如简鹿文件批量重命名工具&#xff0c;可以极大地简化这一过程。本文将详细介绍如何利用该工具对 MP3 音频文件进行重命名。 步骤一&am…

快速上手非关系型数据库-MongoDB

简介 MongoDB 是一个基于文档的 NoSQL 数据库&#xff0c;由 MongoDB Inc. 开发。 NoSQL&#xff0c;指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写&#xff0c;是对不同于传统的关系型数据库的数据库管理系统的统称。 MongoDB 的设计理念是为了应对大数据量、…

【C++学习笔记】深入理解虚函数和多态

文章目录 1. 基本概念1.1 虚函数1.2 虚函数表1.3 虚函数表指针1.4 虚函数表在支持多态方面的工作原理 2. 类对象在内存中的布局参考 1. 基本概念 1.1 虚函数 类的成员函数&#xff0c;并不占用类对象的内存空间。 类中有虚函数&#xff0c;编译器会向类中插入一个看不见的成…

Node.js CSRF 保护指南:示例及启用方法

解释 CSRF 跨站请求伪造 (CSRF/XSRF) 是一种利用用户权限劫持会话的攻击。这种攻击策略允许攻击者通过诱骗用户以攻击者的名义提交恶意请求,从而绕过我们的安全措施。 CSRF 攻击之所以可能发生,是因为两个原因。首先,CSRF 攻击利用了用户无法辨别看似合法的 HTML 元素是否…

【Linux】VSCode用法

描述 部分图片和经验来源于网络&#xff0c;若有侵权麻烦联系我删除&#xff0c;主要是做笔记的时候忘记写来源了&#xff0c;做完笔记很久才写博客。 专栏目录&#xff1a;记录自己的嵌入式学习之路-CSDN博客 目录 1 安装环境及运行C/C 1.1 安装及配置步骤 1.2 运…

来聊聊JVM中安全点的概念

文章目录 写在文章开头详解safepoint基本概念什么是安全点?为什么需要安全点JVM如何让线程跑到最近的安全点线程什么时候需要进入安全点JVM如何保证线程高效进入安全点如何设置安全点用一次GC解释基于安全点的STW实践-基于主线程休眠了解安全点的工作过程代码示例基于日志印证…

Nginx — http、server、location模块下配置相同策略优先级问题

一、配置优先级简述 在 Nginx 中&#xff0c;http、server、location 模块下配置相同策略时是存在优先级的&#xff0c;一般遵循 “范围越小&#xff0c;优先级越高” 的原则&#xff0c;下面为你详细介绍&#xff1a; 1. 配置继承关系 http 块&#xff1a;作为全局配置块&…

线性代数—向量与矩阵的范数(Norm)

参考链接&#xff1a; 范数&#xff08;Norm&#xff09;——定义、原理、分类、作用与应用 - 知乎 带你秒懂向量与矩阵的范数(Norm)_矩阵norm-CSDN博客 什么是范数&#xff08;norm&#xff09;&#xff1f;以及L1,L2范数的简单介绍_l1 norm-CSDN博客 范数&#xff08;Norm…

【业务领域】电脑主板芯片电路结构

前言 由前几期视频合集(零基础自学计算机故障排除—7天了解计算机开机过程)&#xff0c;讲解了POST的主板软启动过程&#xff1b;有不少网友留言、私信来问各种不开机的故障&#xff0c;但大多网友没能能过我们的这合集视频&#xff0c;很好的理清思路&#xff0c;那这样的情况…

pandas读取Excel数据(.xlsx和.xls)到treeview

对于.xls文件&#xff0c;xlrd可能更合适&#xff0c;但需要注意新版本的xlrd可能不支持xlsx&#xff0c;不过用户可能同时需要处理两种格式&#xff0c;所以可能需要结合openpyxl和xlrd&#xff1f;或者直接用pandas&#xff0c;因为它内部会处理这些依赖。 然后&#xff0c;…

JVM——垃圾收集策略

GC的基本问题 什么是GC&#xff1f; GC 是 garbage collection 的缩写&#xff0c;意思是垃圾回收——把内存&#xff08;特别是堆内存&#xff09;中不再使用的空间释放掉&#xff1b;清理不再使用的对象。 为什么要GC&#xff1f; 堆内存是各个线程共享的空间&#xff0c…

马克·雷伯特:用算法让机器人飞奔的人

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 马克雷伯特:用算法让机器人飞奔的人 一、天才的起点 在机器人领域,有一个名字如雷贯耳——马克雷伯特(Marc Raibert)。作为波士顿动力公司(Boston…

信创系统资产清单采集脚本:主机名+IP+MAC 一键生成 CSV

原文链接&#xff1a;信创系统资产清单采集脚本&#xff1a;主机名IPMAC 一键生成 CSV Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在信创终端操作系统上自动批量采集主机名、IP 和 MAC 并导出为 CSV 表格的实战文章&#xff01;本方案使用 sshpass 和 Bash 脚本…