【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的发展…...
别再死记参数了!深入Halcon measure_pos算子底层:从高斯滤波到亚像素边缘的完整推导
深入解析Halcon measure_pos算子:从数学原理到工程调优 在工业视觉检测领域,亚像素级边缘检测一直是核心难题。当我们使用Halcon这类专业工具时,measure_pos算子看似简单易用,但真正理解其底层机制的人却寥寥无几。本文将带您穿透…...
Open-Shell-Menu:让Windows界面回归高效与个性化的开源解决方案
Open-Shell-Menu:让Windows界面回归高效与个性化的开源解决方案 【免费下载链接】Open-Shell-Menu Classic Shell Reborn. 项目地址: https://gitcode.com/gh_mirrors/op/Open-Shell-Menu 当项目经理王工在Windows 11电脑上第5次点击"所有应用"按钮…...
2026年知网AIGC检测卡在20%降不下去怎么办?这3招解决
直接说方案,不绕弯子。知网AIGC检测不通过、降AIGC率、降AI这个问题,核心是找准降不下去的原因,再用对工具。 我花了一个月测出来的结论:用嘎嘎降AI(www.aigcleaner.com) 全文上传,基本能解决大…...
如何用Bypass Paywalls Clean突破付费墙限制?技术解析与实战指南
如何用Bypass Paywalls Clean突破付费墙限制?技术解析与实战指南 【免费下载链接】bypass-paywalls-chrome-clean 项目地址: https://gitcode.com/GitHub_Trending/by/bypass-paywalls-chrome-clean 在数字内容付费墙日益严密的今天,Bypass Payw…...
前端测试的学习阶段,由基础到进阶的过程认识.....
前言:突然想起刚入行的学习感悟,一个知识点不懂的背后,是整个知识体系的欠缺, 那会从后端转入前端(非科班)有时候一个报错不知道从何找起,一、单元测试 【已经案例和知识相结合,可看…...
数据库存储有什么作用
数据库存储就是把数据安全、规范、高效地存起来,方便以后用,核心作用可以分成这几块:1. 持久化保存程序关掉、电脑重启,数据不会丢失不像内存一断电就清空,数据库存在硬盘里长期保存2. 统一管理数据把零散的文件、记录…...
终极指南:Brontes区块链分析引擎的Cargo.toml依赖管理策略
终极指南:Brontes区块链分析引擎的Cargo.toml依赖管理策略 【免费下载链接】brontes A blazingly fast general purpose blockchain analytics engine specialized in systematic mev detection 项目地址: https://gitcode.com/GitHub_Trending/br/brontes B…...
从CNN到Mamba:为什么这个轻量级双分支结构在医学图像分类中表现更好?
从CNN到Mamba:轻量级双分支结构如何重塑医学图像分类范式 医学影像分析正面临前所未有的挑战——随着CT、MRI、超声等成像技术的普及,每天产生的医学图像数据呈指数级增长。传统CNN架构在应对高分辨率医学图像时,往往陷入局部特征提取的局限&…...
零域名部署实战:阿里云ECS与宝塔面板的IP直连建站指南
1. 为什么选择IP直连建站? 很多刚接触服务器部署的朋友可能会疑惑:为什么不用域名直接访问网站?其实IP直连建站特别适合以下几种场景。比如你正在开发一个内部测试项目,需要快速让团队成员查看效果;或者你要给客户演示…...
实战演练:基于Copaw下载的博客代码,在快马平台上快速构建并部署可访问的全栈应用
今天想和大家分享一个实战经验:如何基于Copaw下载的代码,在InsCode(快马)平台上快速构建并部署一个全栈博客应用。整个过程非常流畅,特别适合想快速验证想法的开发者。 项目背景与需求分析 最近在Copaw上找到一个博客系统的代码骨架&#x…...
