【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的发展…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...

WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...
简单介绍C++中 string与wstring
在C中,string和wstring是两种用于处理不同字符编码的字符串类型,分别基于char和wchar_t字符类型。以下是它们的详细说明和对比: 1. 基础定义 string 类型:std::string 字符类型:char(通常为8位)…...