【Redis】Redis 中地理位置功能 Geospatial 了解一下?
文章目录
- 前言
- 一、Geospatial Indexes 的数据结构
- 二、常用命令
- 三、实用场景示例
- 1. 找出某一经纬度周围的餐馆
- 2. 按照距离排序查询景点
- 四、在实际开发中,需要注意以下几点:
前言
Geospatial Indexes 是 Redis 提供的一种数据结构,用于存储和查询地理位置信息。它可以将地理位置的经度和纬度编码为二维平面上的点,并支持根据距离或矩形区域查询附近的地理位置点,这使得它在很多场景下被广泛应用,比如 LBS(Location Based Service)、智能推荐、出行规划等。
Redis 中 Geospatial Indexes 是通过有序集合实现的,其内部使用 zset 数据类型来存储地理位置点的经纬度和成员信息。其中,经纬度以浮点数表示,成员信息则可以是用户 ID、商铺名称等。
在使用 Geospatial Indexes 时,我们需要注意以下几个方面:
- 地理位置点的经纬度采用 WGS-84 坐标系表示;
- 距离单位默认为米,可以通过参数设置为其他单位;
- 矩形区域查询默认采用左闭右开的方式,即包括左边界,不包括右边界。
一、Geospatial Indexes 的数据结构
Geospatial Indexes 在 Redis 中是通过 zset 实现的,其中地理位置点的经纬度被编码为 zset 中每个 member 的分数。具体来说,Redis 在将经纬度编码为分数时,使用了 zset 的有序性质,将其转化为一个唯一的、不可重复的浮点数。
例如,如果我们要存储以下三个地理位置点:
- 北京 39.9042° N, 116.4074° E
- 上海 31.2304° N, 121.4737° E
- 广州 23.1291° N, 113.2644° E
则可以将经纬度编码为分数,存入 zset 中,如下所示:
- ZADD city_geo_location 116.4074 39.9042 “北京”
- ZADD city_geo_location 121.4737 31.2304 “上海”
- ZADD city_geo_location 113.2644 23.1291 “广州”
此时,zset 中的每个 member 都代表了一个地理位置点,其分数则代表了该点的唯一标识,在进行距离或矩形区域查询时将会用到。
二、常用命令
Redis 中的 Geospatial Indexes 提供了一组命令来管理和查询地理位置数据,包括以下命令:
-
GEOADD:向有序集合中添加一个或多个地理位置元素。
-
语法:GEOADD key longitude latitude member [longitude latitude member …]
-
参数:
- key:必需,要添加元素的有序集合的键名。
- longitude:必需,要添加元素的经度值,范围为 -180 到 180 度。
- latitude:必需,要添加元素的纬度值,范围为 -90 到 90 度。
- member:必需,要添加元素的成员名,必须为字符串类型。
-
示例:GEOADD restaurants 139.7329 35.6634 “Sushi Dai” 139.7712 35.7100 “Afuri Ramen” 139.7198 35.7101 “Komoro Soba”
-
-
GEOPOS:获取指定成员在有序集合中的经纬度坐标。
-
语法:GEOPOS key member [member …]
-
参数:
- key:必需,要获取经纬度坐标的有序集合的键名。
- member:必需,要获取经纬度坐标的元素的成员名,可以指定多个成员名。
-
返回值:一个二维数组,每个子数组表示一个成员的经纬度坐标,每个子数组包含两个元素,分别表示经度和纬度。
-
示例:GEOPOS restaurants “Sushi Dai” “Komoro Soba”,返回值为 [[“139.7329”,“35.6634”],[“139.7198”,“35.7101”]]
-
-
GEODIST:获取有序集合中两个成员之间的距离。
-
语法:GEODIST key member1 member2 [unit]
-
参数:
- key:必需,要计算距离的有序集合的键名。
- member1:必需,第一个成员的名字。
- member2:必需,第二个成员的名字。
- unit:可选,默认为米,表示要返回的距离单位,可以是以下四种单位之一:“m”(米)、“km”(千米)、“mi”(英里)、“ft”(英尺)。
-
返回值:两个成员之间的距离值,以指定的单位表示。
-
示例:GEODIST restaurants “Sushi Dai” “Komoro Soba” km,返回值为 “2.0499”
-
-
GEORADIUS:按照给定的经纬度坐标和半径范围查找有序集合中符合条件的元素。
-
语法:GEORADIUS key longitude latitude radius m|km|mi|ft [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]
-
参数:
- key:必需,要查询的有序集合的键名。
- longitude:必需,中心点的经度值,范围为 -180 到 180 度。
- latitude:必需,中心点的纬度值,范围为 -90 到 90 度。
- radius:必需,半径范围,可以是以下格式之一:m(米)、km(千米)、mi(英里)或 ft(英尺)。
- m|km|mi|ft:必需,半径范围的单位,可以是以下四种单位之一:“m”(米)、“km”(千米)、“mi”(英里)、“ft”(英尺)。
- WITHCOORD:可选,指示返回结果是否包含元素的经纬度坐标。如果指定了该参数,则结果将包含经纬度坐标,否则不包含经纬度坐标。
- WITHDIST:可选,指示返回结果是否包含元素与中心点之间的距离值。如果指定了该参数,则结果将包含距离值,否则不包含距离值。
- ASC|DESC:可选,指示返回结果是否按照距离值(从小到大)排序。如果指定了该参数,则结果将按距离值排序,否则默认按有序集合中的顺序返回结果。
- COUNT count:可选,指示返回结果的数量限制。如果指定了该参数,则结果将最多包含 count 个元素,否则返回所有符合条件的元素。
-
返回值:若干个符合条件的元素(根据查询参数而定),每个元素由成员名、经度坐标和纬度坐标组成。如果指定了 WITHDIST 参数,则每个元素还包含距离值。如果指定了 WITHCOORD 参数,则每个元素还包含经纬度坐标。
-
示例:GEORADIUS restaurants 139.7329 35.6634 5 km WITHCOORD WITHDIST,表示查找以经纬度 (139.7329, 35.6634) 为中心,半径为 5 公里范围内的所有元素,并返回它们与中心点之间的距离值和经纬度坐标。
-
-
GEORADIUSBYMEMBER:按照给定的成员名和半径范围查找有序集合中符合条件的元素。
-
语法:GEORADIUSBYMEMBER key member radius m|km|mi|ft [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]
-
参数:
- key:必需,要查询的有序集合的键名。
- member:必需,中心点的成员名。
- radius:必需,半径范围,可以是以下格式之一:m(米)、km(千米)、mi(英里)或 ft(英尺)。
- m|km|mi|ft:必需,半径范围的单位,可以是以下四种单位之一:“m”(米)、“km”(千米)、“mi”(英里)、“ft”(英尺)。
- WITHCOORD:可选,指示返回结果是否包含元素的经纬度坐标。如果指定了该参数,则结果将包含经纬度坐标,否则不包含经纬度坐标。
- WITHDIST:可选,指示返回结果是否包含元素与中心点之间的距离值。如果指定了该参数,则结果将包含距离值,否则不包含距离值。
- ASC|DESC:可选,指示返回结果是否按照距离值(从小到大)排序。如果指定了该参数,则结果将按距离值排序,否则默认按有序集合中的顺序返回结果。
- COUNT count:可选,指示返回结果的数量限制。如果指定了该参数,则结果将最多包含 count 个元素,否则返回所有符合条件的元素。
-
返回值:若干个符合条件的元素(根据查询参数而定),每个元素由成员名、经度坐标和纬度坐标组成。如果指定了 WITHDIST 参数,则每个元素还包含距离值。如果指定了 WITHCOORD 参数,则每个元素还包含经纬度坐标。
-
示例:GEORADIUSBYMEMBER restaurants “Sushi Dai” 5 km WITHCOORD WITHDIST,表示查找以成员名 “Sushi Dai” 对应的经纬度为中心,半径为 5 公里范围内的所有元素,并返回它们与中心点之间的距离值和经纬度坐标。
-
-
GEOHASH:获取指定成员在有序集合中的 Geohash 值。
-
语法:GEOHASH key member [member …]
-
参数:
- key:必需,要获取 Geohash 值的有序集合的键名。
- member:必需,要获取 Geohash 值的元素的成员名,可以指定多个成员名。
-
返回值:一个数组,每个元素表示一个成员的 Geohash 值。
-
示例:GEOHASH restaurants “Sushi Dai” “Komoro Soba”,返回值为 [“xn7743”,“xn773w”]
-
-
GEOINTERSECTS:检查指定的两个成员之间是否存在任何交集。
-
语法:GEOINTERSECTS key member1 member2
-
参数:
- key:必需,要检查交集的有序集合的键名。
- member1:必需,第一个成员的名字。
- member2:必需,第二个成员的名字。
-
返回值:一个整数值,如果两个成员之间存在交集,则返回 1,否则返回 0。
-
示例:GEOINTERSECTS restaurants “Sushi Dai” “Komoro Soba”,如果 “Sushi Dai” 和 “Komoro Soba” 代表的位置之间存在任何交集,则返回 1,否则返回 0。
-
三、实用场景示例
1. 找出某一经纬度周围的餐馆
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;import java.util.List;public class RestaurantFinder {private final static String HOST = "localhost";private final static int PORT = 6379;private final static int TIMEOUT = 5000;private final static String PASSWORD = "";private static final String KEY_RESTAURANT_LOCATION = "restaurant_location";private static Jedis jedis = null;static {try {jedis = new Jedis(HOST, PORT, TIMEOUT);if (!PASSWORD.isEmpty()) {jedis.auth(PASSWORD);}} catch (Exception e) {e.printStackTrace();}}/*** 添加餐馆的经纬度信息** @param longitude 经度* @param latitude 纬度* @param name 餐馆名称* @return*/public Long addRestaurant(double longitude, double latitude, String name) {return jedis.geoadd(KEY_RESTAURANT_LOCATION, longitude, latitude, name);}/*** 根据给定的坐标和半径查找周围的餐馆** @param longitude 经度* @param latitude 纬度* @param radius 半径,单位为米* @return*/public List<GeoRadiusResponse> findNearbyRestaurants(double longitude, double latitude, double radius) {return jedis.georadius(KEY_RESTAURANT_LOCATION, longitude, latitude, radius, GeoUnit.M);}/*** 测试** @param args*/public static void main(String[] args) {RestaurantFinder finder = new RestaurantFinder();finder.addRestaurant(121.451087, 31.228591, "麦当劳");finder.addRestaurant(121.454987, 31.227568, "星巴克");finder.addRestaurant(121.455831, 31.225719, "肯德基");List<GeoRadiusResponse> restaurants = finder.findNearbyRestaurants(121.453289, 31.228032, 500);for (GeoRadiusResponse restaurant : restaurants) {System.out.println(restaurant.getMemberByString() + " " + restaurant.getDistance());}}
}
2. 按照距离排序查询景点
import redis.clients.jedis.GeoRadiusParam;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;import java.util.List;public class ScenicSpotFinder {private final static String HOST = "localhost";private final static int PORT = 6379;private final static int TIMEOUT = 5000;private final static String PASSWORD = "";private static final String KEY_SPOT_LOCATION = "spot_location";private static Jedis jedis = null;static {try {jedis = new Jedis(HOST, PORT, TIMEOUT);if (!PASSWORD.isEmpty()) {jedis.auth(PASSWORD);}} catch (Exception e) {e.printStackTrace();}}/*** 添加景点的经纬度信息** @param longitude 经度* @param latitude 纬度* @param name 景点名称* @return*/public Long addScenicSpot(double longitude, double latitude, String name) {return jedis.geoadd(KEY_SPOT_LOCATION, longitude, latitude, name);}/*** 根据给定的坐标和半径查找周围的景点,并按照距离排序** @param longitude 经度* @param latitude 纬度* @param radius 半径,单位为米* @return*/public List<GeoRadiusResponse> findNearbyScenicSpots(double longitude, double latitude, double radius) {GeoRadiusParam geoRadiusParam = GeoRadiusParam.geoRadiusParam().sortAscending();return jedis.georadius(KEY_SPOT_LOCATION, longitude, latitude, radius, GeoUnit.M, geoRadiusParam);}/*** 测试** @param args*/public static void main(String[] args) {ScenicSpotFinder finder = new ScenicSpotFinder();finder.addScenicSpot(121.451087, 31.228591, "东方明珠");finder.addScenicSpot(121.454987, 31.227568, "外滩");finder.addScenicSpot(121.455831, 31.225719, "人民广场");List<GeoRadiusResponse> spots = finder.findNearbyScenicSpots(121.453289, 31.228032, 500);for (GeoRadiusResponse spot : spots) {System.out.println(spot.getMemberByString() + " " + spot.getDistance());}}
}## 3. 根据经纬度计算两点距离
java复制代码import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;public class DistanceCalculator {private final static String HOST = "localhost";private final static int PORT = 6379;private final static int TIMEOUT = 5000;private final static String PASSWORD = "";private static Jedis jedis = null;static {try {jedis = new Jedis(HOST, PORT, TIMEOUT);if (!PASSWORD.isEmpty()) {jedis.auth(PASSWORD);}} catch (Exception e) {e.printStackTrace();}}/*** 计算两个经纬度之间的距离** @param longitude1 经度1* @param latitude1 纬度1* @param longitude2 经度2* @param latitude2 纬度2* @return*/public Double calculateDistance(double longitude1, double latitude1, double longitude2, double latitude2) {return jedis.geodist("distance", longitude1, latitude1, longitude2, latitude2, GeoUnit.M);}/*** 测试** @param args*/public static void main(String[] args) {DistanceCalculator calculator = new DistanceCalculator();double distance = calculator.calculateDistance(121.453289, 31.228032, 121.451087, 31.228591);System.out.println(distance);}
}
四、在实际开发中,需要注意以下几点:
- 每个位置都需要一个唯一的标识符。
- 经度和纬度的值需要使用正确的格式。
- 半径的单位为米。
- Redis 地理位置功能支持多种查询方式,例如矩形查询、关键字查询等,需要根据实际需求进行选择。
相关文章:
【Redis】Redis 中地理位置功能 Geospatial 了解一下?
文章目录 前言一、Geospatial Indexes 的数据结构二、常用命令三、实用场景示例1. 找出某一经纬度周围的餐馆2. 按照距离排序查询景点 四、在实际开发中,需要注意以下几点: 前言 Geospatial Indexes 是 Redis 提供的一种数据结构,用于存储和…...
Qt Qml 实现键鼠长时间未操作锁屏
文章目录 摘要实现思路键盘鼠标监控百度到的方法我的自己方法 最后 关键字: Qt、 Qml、 QInputEvent 、 QStandardItem、 eventFilter 摘要 今日需求: 项目中需要实时检测用户是否长时间为操作键盘和鼠标,如果超过预设时间未操作键盘和…...
常用的数字高程模型(DEM)数据介绍,附免费下载
常用的数字高程模型(DEM)数据: ETOPO(1.8千米) ETOPO是一种地形高程数据,由NGDC美国地球物理中心发布,与大多数高程数据不同的是,它还包含海底地形数据。 SRTM15(450…...
字节跳动面试挂在2面,复盘后,决定二战.....
先说下我基本情况,本科不是计算机专业,现在是学通信,然后做图像处理,可能面试官看我不是科班出身没有问太多计算机相关的问题,因为第一次找工作,字节的游戏专场又是最早开始的,就投递了…...
简述熔断、限流、降级
高并发场景指的是在大量用户同时访问服务时,服务能够保持稳定和高效运行的能力。 常用的解决高并发场景下服务不可用问题的技术手段包括熔断、限流和降级: - 熔断:当服务的错误率超过一定阈值时,熔断器会自动断开服务的调用&…...
Maven 工具
Maven 工具 Maven简介Maven 基础概念创建 Maven项目依赖配置生命周期与插件分模块开发聚合和继承聚合继承聚合与继承的区别 属性版本管理多环境配置与应用私服 Maven简介 Maven 本质是一个项目管理工具,将项目开发和管理过程抽象成一个项目对象模型(POM…...
iptables扩展匹配条件
文章目录 1. multiport模块2. iprange模块3. string模块4. time模块5. icmp模块6. connlimit模块7. limit模块8.tcp扩展模块9.state模块10 Iptables自定义链1.1 为什么要使用自定义链1.2 创建自定义链1.3 引用自定义链1.4 重命名自定义链1.5 删除自定义链 1. multiport模块 常…...
直播录音时准备一副监听耳机,实现所听即所得,丁一号G800S上手
有些朋友在录视频还有开在线会议的时候,都会遇到一个奇怪的问题,就是自己用麦克风收音的时候,自己的耳机和别人的耳机听到的效果不一样,像是音色、清晰度不好,或者是缺少伴奏以及背景音嘈杂等,这时候我们就…...
回归测试最小化(贪心算法,帕累托支配)
回归测试最小化(贪心算法,帕累托支配) 介绍 有时我们不能只是重新运行我们的测试(例如,当我们 换界面)。 回归测试可能很昂贵: (1)一些公司通宵运行回归测试套件。 (2) 对于嵌入式系统,我们可能必须测试正在使用的软件࿰…...
Python系列模块之标准库shutil详解
感谢点赞和关注 ,每天进步一点点!加油! 目录 一、shutil介绍 二 、使用详解 2.1 复制函数 2.1.1 shutil.copy 2.1.2 shutil.copy2 2.1.3 shutil.copyfile 2.1.4 shutil.copytree 2.2 移动文件 2.2.1 shutil.move 2.3 删除文件 2.3…...
pb如何播放Flash
---- Flash动画不仅包含动画,还可有声音、超文本连接,同时由于它是矢量格式文件,生成的这种包含动画、声音等的文件(*.swf)很小,非常适 合在网络上传输使用,因而在当前Web网页技术中得到很快发展。本文讨论在PowerBuilder6.5数据库编程中用Flash4提供的控件"Swflas…...
独立成分分析ICA
独立成分分析 ICA 1. 算法原理简介2.源信号与混合信号的差异2.1 独立性 Independence2.2 高斯性 Normality2.3 复杂性 Complexity 3.非高斯性的度量3.1 峭度 Kurtosis 参考文献 blind source separation (BSS) 1. 算法原理简介 mixing得到signal mixture过程: x 1…...
从零开始之如何在React Native中使用导航
好的,让我们开始学习如何在React Native中使用导航。 安装React Navigation 首先,你需要安装React Navigation库。在项目文件夹中打开终端窗口,并运行以下命令: npm install react-navigation/native 或者 yarn add react-nav…...
RAW、RGB 、YUV三种图像格式理解
文章目录 1. 背景2. 相关概念2.1 颜色与色彩空间2.2 RAW图像2.3 RGB图像2.4 YUV图像 3. 分类简图 RAW、RGB 、YUV三种图像格式理解 1. 背景 在工作中,经常听到用来描述图像格式的RAW,RGB与YUV,但一直没有系统的进行了解,处于局部认…...
关于对【mysql存储过程】的理解与简述
【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://blog.csdn.net/m0_69908381/article/details/130857854 出自【进步*于辰的博客】 【存储过程】这个知识点,我在大二下期学习【mys…...
贪吃蛇游戏的制作记录
关于蛇的实现代码 #include "snake.h" #include "globalvar.h" #include <graphics.h> int fangXiang 1;//方向 0 右 1 上 2 左 3 下 int snakeHang[100] { 10,11,12,13,14 };//蛇 每节所在行 int snakeLie[100] { 10,10,10,10,10 };//蛇 每节所…...
Go基础入门
Go是一种现代的、高效的、开源的编程语言,由Google开发。它的语法简洁、易于学习和使用,支持并发编程,特别适合构建网络应用和分布式系统。本篇文章将介绍Go语言的基础语法和常用特性,帮助初学者快速入门。 一、Go语言的基础语法…...
JavaScript教程(二)
BOM浏览器对象模型 什么是BOM BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window;BOM由一系列相关的对象构成,并且每个对象都提供了很多方…...
设计模式之代理模式
代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问。 因为代理类与服务类实现同样的接口,所以代理类能代替服务类提供给客户端。当客户端使用代理类时,代理类能对请求进行处理(例如增加访问控制、缓存请求结果、隐…...
初识MySQL
💕与其抱怨生活的不公,不如积极行动改变它。💕 🐼作者:不能再留遗憾了🐼 🎆专栏:MySQL学习🎆 🚗本文章主要内容:简单了解什么是MySQL、MySQL的发展…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
