Redis - Redis GEO实现经纬度测算距离,附近搜索范围

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增

一、Redis GEO 操作方法

geoadd:添加地理位置的坐标

geopos:获取地理位置的坐标

geodist:计算两个位置之间的距离

georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集

georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合

geohash:返回一个或多个位置对象的 geohash 值

GeoOperations 的 add 方法

org.springframework.data.redis.core.GeoOperations// Add RedisGeoCommands.GeoLocation into key.
Long add(K key, RedisGeoCommands.GeoLocation<M> location)

GeoOperations 的 distance 方法

org.springframework.data.redis.core.GeoOperations// Get the Distance between member1 and member2.
Distance distance(K key, M member1, M member2)

Spring整合

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;@Component
public class GeoUtil {@Autowiredprivate RedisTemplate redisTemplate;/*** 作为存储经纬度列表的key值*/private static final String GEO_KEY = "DISTANCE";/*** 将经纬度信息添加到redis中* @param certId 标识* @param longitude 经度* @param latitude 纬度*/public void geoAdd(String certId, double longitude, double latitude) {GeoOperations geoOperations = redisTemplate.opsForGeo();Point point = new Point(longitude, latitude);RedisGeoCommands.GeoLocation geoLocation = new RedisGeoCommands.GeoLocation(certId, point);geoOperations.add(GEO_KEY, geoLocation);}/*** 两个人之间的距离* @param certId1* @param certId2* @return*/public double distanceBetween(String certId1, String certId2) {GeoOperations geoOperations = redisTemplate.opsForGeo();Distance distance = geoOperations.distance(GEO_KEY, certId1, certId2);return distance.getValue();}/*** 查询距离某个人指定范围内的人,包括距离多少米* @param certId* @param distance* @return*/public Map<String, Double> distanceInclude(String certId, double distance) {Map<String, Double> map = new LinkedHashMap<>();GeoOperations geoOperations = redisTemplate.opsForGeo();RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = geoOperations.radius(GEO_KEY, certId, new Distance(distance), geoRadiusCommandArgs.includeDistance());if (geoResults != null) {Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>> iterator = geoResults.iterator();while (iterator.hasNext()) {GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult = iterator.next();// 与目标点相距的距离信息Distance geoResultDistance = geoResult.getDistance();// 该点的信息RedisGeoCommands.GeoLocation<String> geoResultContent = geoResult.getContent();map.put(geoResultContent.getName(), geoResultDistance.getValue());}}return map;}
}

二、附近搜索功能

引入redis依赖

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.3.0.RELEASE</version>
</dependency>

domain

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel("位置信息")
public class Location {@ApiModelProperty("经度")private Double longitude;@ApiModelProperty("纬度")private Double latitude;@ApiModelProperty("半径")private Double radius;@ApiModelProperty("条数")private Long limit;
}

Service

        String baiduKey =  RedisConstant.KEY_BAIDU_POI + "cities";Map<String, Point> points = new HashMap<>();points.put("shijiazhuang", new Point(114.48, 38.03));points.put("xingtang", new Point(114.54, 38.42));points.put("guangcheng", new Point(114.84, 38.03));points.put("gaoyi", new Point(114.58, 37.62));points.put("zhaoxian", new Point(114.78, 37.76));points.put("jinxing", new Point(114.13, 38.03));points.put("luquan", new Point(114.03, 38.08));points.put("xinle", new Point(114.67, 38.33));points.put("zhengding", new Point(114.56, 38.13));RedisUtil.opsForGeo().add(baiduKey,points);//设置当前位置// // Point 中 x:经度"longitude":114.56,y:纬度"latitude":38.13Point point = new Point(114.56, 38.13);//设置半径范围 (KILOMETERS 千米;METERS 米)Metric metric = RedisGeoCommands.DistanceUnit.KILOMETERS;Distance distance = new Distance(3, metric);Circle circle = new Circle(point, distance);//设置参数 包括距离、坐标、条数RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance()//包含距离.includeCoordinates();//包含经纬度
//                .sortAscending()//正序排序
//                .limit(50); //条数GeoResults<RedisGeoCommands.GeoLocation<String>> radius = RedisUtil.opsForGeo().radius(baiduKey,circle, geoRadiusCommandArgs);if (geoResults != null) {Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>> iterator = geoResults.iterator();while (iterator.hasNext()) {GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult = iterator.next();// 与目标点相距的距离信息Distance geoResultDistance = geoResult.getDistance();// 该点的信息RedisGeoCommands.GeoLocation<String> geoResultContent = geoResult.getContent();}}

Redis存入单个,批量存

/*** Redis缓存酒店ID,以及经纬度* 百度经纬度(默认存百度经纬度,即使前端传的 高德,谷歌,也将其转为百度,否则即数据错误)* @param newHotelRecommend* @return*/private void redisCacheLongitudeAndLatitude(HotelRecommendNew newHotelRecommend){String baiduKey = RedisKeyConstants.KEY_RECOMMEND_HOTEL + newHotelRecommend.getCityCode();// 百度经纬度(默认存百度经纬度,即使前端传的 高德,谷歌,也将其转为百度,否则即数据错误)if (StringUtils.isNotEmpty(newHotelRecommend.getCoordinatesBaidu())){// 纬度 latitude;经度 longitude;苏州经纬度:纬度31.29.9468;经度121.16.0530String[] splitBaidu = newHotelRecommend.getCoordinatesBaidu().split(",");String latBaidu = splitBaidu[0];String lngBaidu = splitBaidu[1];// prefix + 城市code + 高德,百度类型// Point 中 x:经度"longitude":114.56,y:纬度"latitude":38.13redisCache.redisTemplate.opsForGeo().add(baiduKey ,new Point(Double.parseDouble(lngBaidu),Double.parseDouble(latBaidu)),newHotelRecommend.getHotelId().toString());}}/*** Redis缓存酒店ID,以及经纬度* 百度经纬度(默认存百度经纬度,即使前端传的 高德,谷歌,也将其转为百度,否则即数据错误)* @param newHotelRecommendList* @return*/private void batchRedisCacheLongitudeAndLatitude(List<HotelRecommendNew> newHotelRecommendList){Map<Integer,List<HotelRecommendNew>> groupCityMap = newHotelRecommendList.stream().collect(Collectors.groupingBy(HotelRecommendNew::getCityCode));groupCityMap.entrySet().stream().forEach((Map.Entry<Integer, List<HotelRecommendNew>> entry) -> {String baiduKey = RedisKeyConstants.KEY_RECOMMEND_HOTEL + entry.getKey();Map<String,Point> pointMap = new HashMap<>();entry.getValue().stream().forEach(hotelRecommendNew -> {// 百度经纬度(默认存百度经纬度,即使前端传的 高德,谷歌,也将其转为百度,否则即数据错误)if (StringUtils.isNotEmpty(hotelRecommendNew.getCoordinatesBaidu())){// 纬度 Latitude;经度 longitude;苏州经纬度:纬度31.29.9468;经度121.16.0530String[] splitBaidu = hotelRecommendNew.getCoordinatesBaidu().split(",");String latBaidu = splitBaidu[0];String lngBaidu = splitBaidu[1];// Point 中 x:经度"longitude":114.56,y:纬度"latitude":38.13pointMap.put(hotelRecommendNew.getHotelId().toString(),new Point(Double.parseDouble(lngBaidu),Double.parseDouble(latBaidu)));}});// prefix + 城市code + 高德,百度类型 (批量加入)redisCache.redisTemplate.opsForGeo().add(baiduKey,pointMap);});}

存入Redis数据

测试数据

POST http://localhost:6001/geo/city
Content-Type: application/json{"longitude": 114.56,"latitude": 38.13,"radius": 100000,"limit": 10
}

返回结果


{"code": 200,"message": "操作成功","data": {"averageDistance": {"value": 31642.19217777778,"metric": "METERS","unit": "m","normalizedValue": 0.004961039905191403},"content": [{"content": {"name": "zhengding","point": {"x": 114.55999821424484,"y": 38.12999923666221}},"distance": {"value": 0.1778,"metric": "METERS","unit": "m","normalizedValue": 2.787647866453794E-8}},{"content": {"name": "shijiazhuang","point": {"x": 114.55999821424484,"y": 38.02999941748397}},"distance": {"value": 13144.3531,"metric": "METERS","unit": "m","normalizedValue": 0.0020608452123245394}},{"content": {"name": "xinle","point": {"x": 114.55999821424484,"y": 38.329998875018696}},"distance": {"value": 24232.5609,"metric": "METERS","unit": "m","normalizedValue": 0.0037993164618445796}},{"content": {"name": "guangcheng","point": {"x": 114.55999821424484,"y": 38.02999941748397}},"distance": {"value": 26919.7324,"metric": "METERS","unit": "m","normalizedValue": 0.004220626242427844}},{"content": {"name": "xingtang","point": {"x": 114.55999821424484,"y": 38.419999219223335}},"distance": {"value": 32302.7819,"metric": "METERS","unit": "m","normalizedValue": 0.005064610857371048}},{"content": {"name": "jinxing","point": {"x": 114.55999821424484,"y": 38.02999941748397}},"distance": {"value": 39255.7243,"metric": "METERS","unit": "m","normalizedValue": 0.006154732063610425}},{"content": {"name": "zhaoxian","point": {"x": 114.55999821424484,"y": 37.760000919591185}},"distance": {"value": 45453.0791,"metric": "METERS","unit": "m","normalizedValue": 0.007126388018946599}},{"content": {"name": "luquan","point": {"x": 114.55999821424484,"y": 38.07999932707309}},"distance": {"value": 46718.8049,"metric": "METERS","unit": "m","normalizedValue": 0.00732483559070619}},{"content": {"name": "gaoyi","point": {"x": 114.55999821424484,"y": 37.62000066579741}},"distance": {"value": 56752.5152,"metric": "METERS","unit": "m","normalizedValue": 0.00889797682301274}}]}
}Response code: 200; Time: 92ms; Content length: 1844 bytes

RedisGEO实现附近搜索功能_华安小书童的博客-CSDN博客

利用Redis的Geo功能实现查找附近的位置! - 知乎

RedisGEO实现附近搜索功能_华安小书童的博客-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ArcGIS Pro二次开发】(43):线闭合

当我们需要将多段线【polyline】转为面【polygon】的时候&#xff0c;必须保证线是闭合的&#xff0c;不然是无法生成面的&#xff0c;如下图&#xff1a; 如果cad线段&#xff0c;可以在属性里将闭合选项设置为是&#xff0c;实现线的闭合&#xff1a; 但如果是在ArcGIS Pro里…

C++【初识哈希】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; C修行之路 &#x1f383;操作环境&#xff1a; Visual Studio 2019 版本 16.11.17 文章目录 &#x1f307;前言&#x1f3d9;️正文1、哈希思想2、哈希函数2.1、哈希函数的设计原则2.2、常见的哈希函数 3、哈希…

云原生——什么是云原生?

❄️作者介绍&#xff1a;奇妙的大歪❄️ &#x1f380;个人名言&#xff1a;但行前路&#xff0c;不负韶华&#xff01;&#x1f380; &#x1f43d;个人简介&#xff1a;云计算网络运维专业人员&#x1f43d; 前言 伴随云计算的滚滚浪潮&#xff0c;云原生(CloudNative…

kubernetes核心概念 controller

kubernetes核心概念 Controller 一、pod控制器controller 1.1 Controller作用及分类 controller用于控制pod 参考: https://kubernetes.io/zh/docs/concepts/workloads/controllers/ 控制器主要分为: Deployments 部署无状态应用&#xff0c;控制pod升级,回退ReplicaSet 副…

ROS自带OpenCV和本地OpenCV版本冲突问题解决

1、报错信息 首先catkin_make编译功能包没有任何问题&#xff0c;100%生成目标文件&#xff0c;但是报了警告&#xff1a;库文件libmyslam.so需要的是libopencv_core.so.3.4&#xff0c;可能会与libopencv_core.so.3.2冲突。根据工程经验&#xff0c;警告不用管&#xff0c;直…

从浏览器输入url到页面加载(六)前端必须了解的路由器和光纤小知识

前言 上一章我们说到了数据包在网线中的故事&#xff0c;说到了双绞线&#xff0c;还说到了麻花。这一章继续沿着这条线路往下走&#xff0c;说一些和cdn以及路由器相关&#xff0c;运营商以及光纤相关的小知识&#xff0c;前端同学应该了解一下的 目录 前言 1. CDN和路由器…

Vue中watch与computed区别

<body><div id"root">姓&#xff1a;<input type"text" v-model"firstName"><br/><br/>名&#xff1a;<input type"text" v-model"lastName"><br/><br/>全名&#xff1a;&…

Spring:Bean

Bean 概述配置方式自动装配继承与依赖作用域外部属性文件的使用 概述 Spring 容器负责管理依赖注入&#xff0c;它将被管理的对象都称为 bean 。我们通过 xml 文件配置方式进行对 bean 的声明和管理。 写法如下&#xff1a; <beans><bean id"bean的唯一标识符…

EasyExcel实现execl导入导出

引言 在实际开发中&#xff0c;处理 Excel 文件是一个常见的需求。EasyExcel 是一个基于 Java 的开源库&#xff0c;提供了简单易用的 API&#xff0c;可以方便地读取和写入 Excel 文件。本文将介绍如何使用 EasyExcel 实现 Excel 导入功能&#xff0c;以及一些相关的技巧和注…

qt for android 开发之tcp通讯

简介 通过TCP使PC和android手机相互通讯。 准备 使用QT的网络模块 QT core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT widgets.h 定义TCP接口 #include <QTcpSocket>class MainWindow : public QMainWindow {Q_OBJECTpublic:explicit MainWindow(Q…

计算机中CPU、内存、缓存的关系

CPU&#xff08;Central Processing Unit&#xff0c;中央处理器&#xff09; 内存&#xff08;Random Access Memory&#xff0c;随机存取存储器&#xff09; 缓存&#xff08;Cache&#xff09; CPU、内存和缓存之间有着密切的关系&#xff0c;它们共同构成了计算机系统的核…

网络安全进阶学习第五课——文件上传漏洞

文章目录 一、常见文件上传点二、任意文件上传漏洞三、任意文件上传危害四、webshell五、上传木马所需条件六、木马上传流程七、上传绕过1、绕过JS验证1&#xff09;Burpsuite剔除响应JS。2&#xff09;浏览器审计工具剔除JS 2、绕过MIME-Type验证1&#xff09;利用抓包工具&am…