基于Redis的Geo实现附近商铺搜索(含源码)

2023-11-16

微信公众号访问地址基于Redis的Geo实现附近商铺搜索(含源码)

推荐文章:

    1、springBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表;

    2、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据;

    3、基于Redis的Geo实现附近商铺搜索(含源码)

    4、基于Redis实现关注、取关、共同关注及消息推送(含源码)

    5、SpringBoot整合多数据源,并支持动态新增与切换(详细教程)

    6、基于Redis实现点赞及排行榜功能

一、GEO常用命令及使用示范

1.1、GEO的数据结构

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

常见的命令有:

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

案例:添加下面几条数据:

    北京南站(116.378248    39.865275)

    北京站(116.42803     39.903738)

    北京西站(116.322287     39.893729)

0>geoadd  g1 116.378248  39.865275 bjnz 116.42803 39.903738 bjz 116.322287 39.893729 bjxz"3"

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

案例:计算北京西站到北京站的距离

redis6.3:0>geodist g1 bjxz bjz km "9.0916"redis6.3:0>

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

redis6.3:0>geohash g1 bjz1) "wx4g12k21s0"

4、GEOPOS:返回指定member的坐标

redis6.3:0>GEOPOS g1 bjz1) 1) "116.42802804708480835"   2) "39.90373880538094653"

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

6、GEOSEARCH:在指定范围内搜索 member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。(6.2 新功能)。在Redis中,GEOSEARCH命令用于在地理位置的有序集合中,根据给定的位置信息搜索符合条件的成员。

GEOSEARCH命令的语法如下:

GEOSEARCH key    [FROMMEMBER member]    [FROMLONLAT longitude latitude]    [BYRADIUS radius unit]    [WITHCOORDINATES]    [WITHDISTANCES]    [WITHHASH]    [COUNT count]    [ASC|DESC]    [STORE key]    [STOREDIST key]

参数说明:

    key:地理位置的有序集合的key名称。

    FROMMEMBER member:从指定成员开始搜索,返回符合条件的成员。

    FROMLONLAT longitude latitude:从给定的经度和纬度开始搜索,返回符合条件的成员。

    BYRADIUS radius unit:根据指定的半径和单位搜索符合条件的成员。

    WITHCOORD:返回成员的经纬度坐标

    WITHDIST:返回成员与中心位置的距离

    WITHHASH:返回成员的地理哈希值

    COUNT count:限制返回的成员数量。

    ASC|DESC:指定返回结果的排序方式,默认为升序

    STORE key:将搜索结果存储到指定的键名中。

    STOREDIST key:将搜索结果存储到指定的键名中,并返回成员与中心位置的距离。

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

redis6.3:0>geosearch g1 fromlonlat 116.397904 39.909005 byradius 10 km withdist1) 1) "bjz"   2) "2.6361"
2) 1) "bjnz"   2) "5.1452"
3) 1) "bjxz"   2) "6.6723"

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

二、应用案例

1、将店铺信息添加到缓存中

核心代码:

public void shopDataToRedis() {
        // 1.查询店铺信息
        List<Shop> list = query().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);
        }
    }
 

接口调用及结果:

2、根据商铺类型基于Geo实现附近商铺分页滚动查询

业务流程:

核心代码:

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

接口调用及展示:

注意事项:

       SpringDataRedis 的 2.3.9 版本并不支持 Redis 6.2 提供的 GEOSEARCH 命令因此我们需要提示其版本,修改自己的 pom.xml,内容如下:

最终结果展示:

三、源码获取方式

     更多优秀文章,请关注个人微信公众号或搜索“程序猿小杨”查阅。然后回复:源码,可以获取该项目对应的源码及表结构,开箱即可使用。

说明:后面redis相关操作的功能都会放在此文件夹中,需要相关功能的,只需要获取最新的资源,替换项目即可

 

       如果大家对相关文章感兴趣,可以关注微信公众号"程序猿小杨",会持续更新优秀文章!欢迎大家 分享、收藏、点赞、在看,您的支持就是我坚持下去的最大动力!谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Redis的Geo实现附近商铺搜索(含源码) 的相关文章

  • Redis发布/订阅:查看当前订阅了哪些频道

    我目前有兴趣查看我拥有的 Redis 发布 订阅应用程序中订阅了哪些频道 当客户端连接到我们的服务器时 我们将它们注册到如下所示的通道 user user id 这样做的原因是我希望能够看到谁 在线 目前 我在不知道客户端是否在线的情况下盲
  • Lua中按字符分割字符串

    我有像这样的字符串 ABC DEF 我需要将它们分开 字符并将两个部分分别分配给一个变量 在 Ruby 中 我会这样做 a b ABC DEF split 显然Lua没有这么简单的方法 经过一番挖掘后 我找不到一种简短的方法来实现我所追求的
  • Redis、会话过期和反向查找

    我目前正在构建一个网络应用程序 并想使用 Redis 来存储会话 登录时 会话会使用相应的用户 ID 插入到 Redis 中 并且过期时间设置为 15 分钟 我现在想实现会话的反向查找 获取具有特定用户 ID 的会话 这里的问题是 由于我无
  • 2 个具有共享 Redis 依赖的 Helm Chart

    目前 我有 2 个 Helm Charts Chart A 和 Chart B Chart A 和 Chart B 对 Redis 实例具有相同的依赖关系 如Chart yaml file dependencies name redis v
  • StackExchange.Redis的正确使用方法

    这个想法是使用更少的连接和更好的性能 连接会随时过期吗 对于另一个问题 redis GetDatabase 打开新连接 private static ConnectionMultiplexer redis private static ID
  • 创建 C++ Redis 模块 - “不导出 RedisModule_OnLoad() 符号”

    我在加载 Redis 模块时遇到一些问题 我只是复制来自的示例https redis io topics modules intro https redis io topics modules intro 但我把它剥下来了 include
  • 如何延长 django-redis 中的缓存 ttl(生存时间)?

    我正在使用 django 1 5 4 和 django redis 3 7 1 我想延长缓存的 ttl 生存时间 当我取回它时 这是示例代码 from django core cache import cache foo cache get
  • 超出 Redis 连接/缓冲区大小限制

    在对我们的应用程序服务器进行压力测试时 我们从 Redis 中得到以下异常 ServiceStack Redis RedisException 无法连接到 redis host 6379 处的 redis 实例 gt System Net
  • 由于配置文件错误,无法启动 Redis 服务器

    我刚刚按照此处的说明安装了 Redis http redis io download http redis io download 当我运行 redis server redis conf 时出现以下错误 FATAL CONFIG FILE
  • ServiceStack.Redis:无法连接:sPort:

    我经常得到 ServiceStack Redis 无法连接 sPort 0 或 ServiceStack Redis 无法连接 sPort 50071 或其他端口号 当我们的网站比较繁忙时 就会出现这种情况 Redis 本身看起来很好 CP
  • 使用环境变量在 redis.conf 中设置动态路径

    我有一个环境变量MY HOME其中有一个目录的路径 home abc 现在 我有一个redis conf文件 我需要像这样设置这个路径 redis conf pidfile MY HOME local var pids redis pid
  • Web API 缓存 - 如何使用分布式缓存实现失效

    我有一个 API 目前不使用任何缓存 我确实有一个正在使用的中间件 它可以生成缓存标头 Cache Control Expires ETag Last Modified 使用https github com KevinDockx HttpC
  • 集合成员的 TTL

    Redis 是否可以不为特定键而是为集合的成员设置 TTL 生存时间 我正在使用 Redis 文档提出的标签结构 数据是简单的键值对 标签是包含与每个标签对应的键的集合 例如 gt SETEX id id 1 100 Lorem ipsum
  • 如何通过ARM模板输出返回Redis的primaryKey?

    我正在尝试借助下面列出的 ARM 模板来部署 Redis 然后返回其主密钥 Azure 门户中 Redis 的 访问密钥 gt 主 下可用的秘密字符串 但是 我从管道 AzureResourceManagerTemplateDeployme
  • 为什么我们需要 Redis 来运行 CKAN?

    我想知道为什么我们需要 Redis 服务器来运行 CKAN 如果需要 为什么 我如何使用 CKAN 配置它 附注 我正在 RHEL7 中运行我的 ckan 实例 Update Redis 已成为一项要求从CKAN 2 7开始 https d
  • 无法使用 ASP.NET 会话状态提供程序连接到 Redis 服务器

    一段时间以来 我一直在尝试用 Redis 替换 ASP NET Session 多个小时与适用于 Redis 的 Microsoft ASP NET 会话状态提供程序 http blogs msdn com b webdev archive
  • .NET Core 依赖注入中的“StackExchange.Redis.ConnectionMultiplexer”应该是“AddSingleton”还是“AddScope”?

    我正在使用以下命令将 Redis 连接添加到 NET CoreStackExchange Redis 目前看起来像这样 public static IServiceCollection AddRedisMultiplexer this IS
  • 具有匹配模式的 ioredis 密钥

    我想用键匹配模式 LOGIN 搜索 Redis 数据库 我在我的应用程序中使用 ioredis 昨天我搜索了整个网络 我得到了一些执行这项工作的选项 如下所示 KEYS 扫描流 Issue import Redis from ioredis
  • 为什么Redis SET性能优于GET?

    根据Redis基准 http redis io topics benchmarkss Redis 可以执行 100 000 SET 操作 秒和 80 000 GET 操作 秒 Redis 是一种内存数据库 这似乎令人惊讶 因为通常人们会认为
  • 如何按键中的值对 Redis 哈希进行排序

    Redis 有没有一种好方法来获取按值排序的哈希中的键 我查看了文档 但没有找到直接的方法 另外有人可以解释一下redis中的排序是如何实现的 以及什么吗 本文档 http redis io commands SORT using hash

随机推荐

  • (转)StyleCop

    微软的StyleCop作为一款代码分析插件 集成到Visual Studio 2008和Visual Studio 2010之中 可以帮助开发人员迅速地理清编程规范问题 对确保软件质量 确保软件开发效率而言 意义非凡 与同样出自微软的另一款
  • python运行时:ModuleNotFoundError: No module named ‘tensorflow‘

    TensorFlow报错 python或者anaconda运行时显示 一般的解决方案 pip install upgrade ignore installed tensorflow 或者 pip install user upgrade i
  • oom killer 详解

    一 oom killer理解和日志分析 知识储备 oom killer日志分析 这是前篇 准备一些基础知识 带着问题看 1 什么是oom killer 是Linux内核设计的一种机制 在内存不足的时候 选择一个占用内存较大的进程并kill掉
  • Navicat使用HTTP通道服务器进行连接mysql数据库(超简单三分钟完成),centos安装nginx和php,docker安装nginx+php合并版

    序言 因为数据库服务器在外网是不能直接连接访问的 但是可以访问网站 网站后台就能访问数据库 所以在此之前 访问数据库的数据是一件非常麻烦的事情 在平时和运维的交流中发现 他们会使用ssh通道进行连接访问数据库 之前并没在意这个东西 直到运维
  • moment函数转换后的时间不正确,带有 “sa“等奇怪的字母

    目录 一 问题 二 解决方法 三 总结 一 问题 1 使用moment函数转换当前日期的格式为 年 月 日 结果转换出来竟然有一些 字母 迷之自信 这不就是这样吗 给了转换格式 给了转换时间 字母就出现这种奇葩的情况 1 代码如下 let
  • 子类化QAbstractTableModel,实现table列排序和整列拖动功能

    子类化QAbstractTableModel 实现table列排序和整列拖动功能 本程序基于Qt5 9 9 Qt creator 4 11 0实现 效果图 1 子类化QAbstractTableModel 主要是实现QAbstractTab
  • 减一天 日期函数_【Excel】日期加减运算法则

    前几天小八和大家分享了如何使用快捷键和函数 快速的输入日期 如果有人不记得了 可以再回顾下 链接如下 Excel 日期木有改 又被领导骂了 除了怎么输入 我想大家更头疼的是 日期怎么参与计算 今天小八就来分享几个日期计算的方法 1 加减1天
  • python实现简易五子棋小游戏(三种方式)

    tkinter库 Python的标准Tk GUI工具包的接口 示例 from tkinter import root Tk 你的ui代码 Label root text hello world pack root mainloop 弹窗结果
  • VS Code集成终端字体修改 & 字体颜色、大小修改方法

    文章目录 VS Code中设置颜色的方法 字体以及字体大小修改 参考 VS Code中设置颜色的方法 通过将以下内容添加到用户设置中 ctrl 并搜索 workbench 然后点击 Edit in settings json 在最后加上如下
  • 国家智慧教育公共服务平台(2023年暑期教师研修)

    前言 最近又要看2023年暑期教师研修高等教育教师专业发展 抓包发现开启倍数无效了 要一个一个点击看视频 岂不是累死人 于是想个办法解放双手 该网站观看视频时 客户端间隔20 50s向服务端发送一个POST请求 服务器每秒返回ts响应 1
  • python数据分析预处理z-score标准化

    一 z score标准化的python代码 import pandas from pandas import read excel from sklearn import preprocessing dataset read excel p
  • 强化学习入门《Easy RL》

    什么是强化学习 强化学习关注的是智能体 Agent 在复杂的环境 Environment 中如何最大化获得的奖励 Reward 智能体和环境两部分组成了强化学习 在强化学习过程中 智能体与环境一直在交互 智能体在环境中获取某个状态后 它会利
  • python学习笔记#2元组和列表

    python学习笔记 2元组和列表 文章目录 python学习笔记 2元组和列表 前言 一 string包含引号 二 复杂数据类型 1 序列 2 tuple 元组 2 list 列表 总结 前言 学习python的复杂数据类型 tuple和
  • 以element ui为例分析前端各种弹窗和对话框的使用场景与区别

    文章目录 摘要 Dialog 对话框 Drawer 抽屉 Notice 通知 MessageBox 弹框 Popconfirm 气泡确认框 Message 消息提示 Notification 通知 Dialog 对话框与Drawer 抽屉的
  • MySQL中的锁机制详解

    概述 事务的隔离性 隔离级别 是由锁来保证的 并发访问数据的情况分为 1 读 读 即并发事务相继读取相同的记录 因为没涉及到数据的更改 所以不会有并发安全问题 允许这种情况发生 2 写 写 即并发事务对相同记录进行修改 会出现脏写问题 因为
  • python flask 网页适应手机端浏览器的编程方法

    1 使用flask在电脑端开发了一个论坛网址 想在手机端浏览看看 却发现根本装不下 并且导航栏元素还消失了 先看电脑端访问是正常的 而手机端导航条不见了 这是因为手机和电脑屏幕分辨率不同导致的 最简单的办法就是添加自适应宽度 并缩放页面 这
  • 异步(延时)逻辑难题,以及采用lua的解决方法

    在网游程序里混过一阵子的程序员大都知道 异步逻辑 是游戏逻辑里最容易失误的地方之一 刷钱 刷经验 不花钱得到道具 然后关服 回档 删号等等等等 其可能造成的危害不胜枚举 而且实际上银行系统之类的地方遇到这种问题就更有趣了 不同团队对此类问题
  • BUUCTF base 第三题Upload-Labs-Linux1比较省事的方法

    1 安装蚁剑 首先下载蚁剑 链接 https pan baidu com s 1O6Ty2Qmk7AVuY9QU CD9gQ fm lk0 提取码 1234 其次解压蚁剑 共两个文件需解压 在AntSword Loader中双击运行 gt
  • PCB线宽与通流量

    PCB通流能力的计算一直缺乏权威的技术方法 公式 经验丰富的Layout工程师依靠个人经验能作出较准确的判断 但是对于Layout新手 不可谓遇上一道难题 PCB的通流能力取决于以下因素 线宽 线厚 铜箔厚度 容许温升 大家都知道 PCB走
  • 基于Redis的Geo实现附近商铺搜索(含源码)

    微信公众号访问地址 基于Redis的Geo实现附近商铺搜索 含源码 推荐文章 1 springBoot对接kafka 批量 并发 异步获取消息 并动态 批量插入库表 2 SpringBoot用线程池ThreadPoolTaskExecuto