Redis GEO地理位置信息的应用

news2024/11/26 13:30:00

Redis GEO地理位置信息的应用

  • Redis GEO
    • 概述
    • 应用场景
    • Redis GEO命令
    • GEO命令演示
  • Redis GEO实现附近人的功能
    • 基础类
    • API接口
    • 接口实现
    • 执行测试

Redis GEO

概述

Redis的GEO操作是一种基于地理位置信息进行操作的功能。它使用经度和纬度坐标来表示地理位置,支持存储地理位置信息用来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。

应用场景

地理围栏:通过设置地理位置的经纬度信息,可以将用户或者车辆等实体绑定在地理围栏内,当实体进出围栏时,可以触发相应的事件。

附近的人:在类似于约会、社交、旅游等场景下,可以通过Redis GEO快速查询周围的人员或景点。

配送服务:通过获取配送地址的经纬度信息,可以找到距离最近的配送员或仓库,并对订单进行分配。

地址查找:在地图应用中,可以通过Redis GEO快速查询某个地址周围的商家或服务设施。

动态信息:在滴滴、Uber等打车应用中,可以实时更新车辆的位置信息,以提供更加准确的车辆推荐和路线规划服务

Redis GEO命令

1.GEOADD添加位置信息

将一个或多个指定的地理位置(经度、纬度、名称)添加到指定的键中。

GEOADD key longitude latitude member [longitude latitude member ...]

添加一个名为cities的键,并将北京、上海、广州三个城市的经纬度和名称添加到该键中

GEOADD cities  116.4074 39.9042 Beijing 121.4737 31.2304 Shanghai 113.2644 23.1291 Guangzhou

GEOADD命令对于经纬度是有要求的:

有效的经度从-180度到180度

有效的纬度从-85.05112878度到85.05112878度

2.GEODIST查询距离

返回两个位置之间的距离。可以选择以米或千米为单位。

GEODIST key member1 member2 [unit]

可选参数unit用于指定计算距离时的单位:

m 表示单位为米

km 表示单位为千米

mi 表示单位为英里

ft 表示单位为英尺

查询北京和上海之间的距离,单位为千米

GEODIST cities Beijing Shanghai km

3.GEOHASH获取指定位置的Geohash值

返回一个或多个位置的Geohash值,该值用于对地理位置进行更快速的范围查找。

GEOHASH key member [member ...]

获取北京的Geohash值

GEOHASH cities Beijing

4.GEOPOS查询地理位置坐标

返回一个或多个位置的经度和纬度。

GEOPOS key member [member ...]

查询广州的经纬度

GEOPOS cities Guangzhou

5.GEORADIUS查找指定范围内的元素

查询给定坐标范围内的所有元素。可以通过设置排序选项来获取按距离排序的结果。

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]

查找距离北京1000公里以内的城市,并按距离升序排列

GEORADIUS cities 116.4074 39.9042 1000 km ASC

6.GEORADIUSBYMEMBER查询给定成员周围的所有元素

查询给定成员周围的所有元素。可以通过设置排序选项来获取按距离排序的结果。

GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]

查找距离上海最近的城市,并返回它们的名称和距离

GEORADIUSBYMEMBER cities Shanghai 100 km WITHDIST

7.ZREM删除成员

从指定键中删除一个或多个成员。

ZREM key member [member ...]

从cities键中删除广州

ZREM cities Guangzhou

GEO命令演示

# 添加位置信息
本机:0>geoadd user:location 121.48941  31.40527 'shagnhai'
"1"
# 添加多个位置信息
本机:0>geoadd user:location 121.47941 31.41527 'shanghai1'  121.47941 31.43527 'shagnhai2'  121.47941 31.40527 'shagnhai3'
"3"



# 计算距离,单位有m km ft(英尺) mi(英里)
# 计算两点间的距离,单位m
本机:0>geodist user:location shanghai shanghai1 m
"1462.1834"
# 千米:km
本机:0>geodist user:location shanghai shanghai1 km
"1.4622"



# geohash 返回一个或多个位置元素的geohash,保存Redis中是用geohash位置52点整数编码
# geohash 将二维经纬度转换成字符串,每个字符串代表一个矩形区域,该矩形区域内的经纬度点都共享一个相同的geohash字符串。
本机:0>geohash user:location shanghai shanghai1
1) "wtw6st1uuq0"
2) "wtw6sqfx5q0"



# geopos 从key里返回指定成员的位置信息
本机:0>geopos user:location shanghai shanghai1
1) 1) "121.48941010236740112"
   2) "31.40526993848380499"

2) 1) "121.47941082715988159"
   2) "31.41526941345740198"



# georadius:给定经纬度为中心,返回键包含的位置元素中,与中心的距离不超过给定最大距离的所有位置元素
# 范围单位:m km mi ft
# withcoord:将位置元素的经纬度一并返回
本机:0>georadius user:location 121.48941 31.40527 3000 m withcoord
1) 1) "shagnhai3"
   2) 1) "121.47941082715988159"
      2) "31.40526993848380499"


2) 1) "shanghai1"
   2) 1) "121.47941082715988159"
      2) "31.41526941345740198"


3) 1) "shanghai"
   2) 1) "121.48941010236740112"
      2) "31.40526993848380499"

# withdist:返回位置元素的同时,将位置元素与中心点间的距离一并返回
本机:0>georadius user:location 121.48941 31.40527 3000 m withdist
1) 1) "shagnhai3"
   2) "949.2411"

2) 1) "shanghai1"
   2) "1462.1719"

3) 1) "shanghai"
   2) "0.0119"

# asc:根据中心位置,按照从近到远的方式返回位置元素
本机:0>georadius user:location 121.48941 31.40527 3000 m withdist asc
1) 1) "shanghai"
   2) "0.0119"

2) 1) "shagnhai3"
   2) "949.2411"

3) 1) "shanghai1"
   2) "1462.1719"


# desc: 根据中心位置,按照从远到近的方式返回位置元素
本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc
1) 1) "shanghai1"
   2) "1462.1719"

2) 1) "shagnhai3"
   2) "949.2411"

3) 1) "shanghai"
   2) "0.0119"


# count:获取指定数量的元素
本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc count 2
1) 1) "shanghai1"
   2) "1462.1719"

2) 1) "shagnhai3"
   2) "949.2411"



# georadiusbymember:和georadius命令类似,都可以找出指定位置范围内的元素,但是georadiusbymember的中心点是由给定位置元素决定的,而不像georadius使用经纬度决定中心点
本机:0>georadiusbymember user:location shanghai 3 km 
1) "shagnhai3"
2) "shanghai1"
3) "shanghai"

Redis GEO实现附近人的功能

基础类

创建NearMeUserVO视图对象,封装响应视图的基本数据信息

@Data
public class NearMeUserVO {

    public Integer id;
   /**
	* 距离
	*/
   public String distance;
}

创建User对象模拟操作用户

    @Data
    public class User {
        private  int id;
    }

API接口

创建添加、更新用户位置信息查询附近用户信息的2个API接口

@RestController
public class NearMeUserController {
    @Autowired
    private INearMeUserService nearMeUserService;

    /**
     * 添加、更新坐标
     *
     * @param lon
     * @param lat
     * @return
     */
    @PostMapping("/updateUserLocation")
    public String updateUserLocation(@RequestParam Float lon, @RequestParam Float lat) {
        nearMeUserService.updateUserLocation(lon, lat);
        return "OK";
    }

    /**
     * 获取附近的人
     * 查询距离指定经纬度一定范围内的用户,并返回结果列表
     *
     * @param radius
     * @param lon
     * @param lat
     * @return
     */
    @GetMapping("/getNearMe")
    public Object nearMe(Integer radius, Float lon, Float lat) {
        List<NearMeUserVO> nearMe = nearMeUserService.findNearMe(radius, lon, lat);
        return nearMe;
    }
}

接口实现

public interface INearMeUserService {

    /**
     * 更新坐标
     *
     * @param lon 经度
     * @param lat 纬度
     */
    void updateUserLocation(Float lon, Float lat);


    /**
     * 获取附近的人
     *
     * @param radius 半径,默认 1000m
     * @param lon    经度
     * @param lat    纬度
     * @return
     */
    List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat);
}
@Service
public class NearMeUserServiceImpl implements INearMeUserService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 用户定位信息cKEY
     */
    private static final String USER_LOCATION_KEY = "user:location";


    public void updateUserLocation(Float lon, Float lat) {
        if (lon == null || lat == null) {
            throw new RuntimeException("获取经度、维度失败");
        }

        // 获取登录用户信息
        User user = this.getLoginUser();
        // 定义key
        String key = "user:location";

        // 将用户地理位置信息存入 Redis
        RedisGeoCommands.GeoLocation geoLocation = new RedisGeoCommands.GeoLocation(user.getId(), new Point(lon, lat));
        redisTemplate.opsForGeo().add(key, geoLocation);
    }

    /**
     * 获取附近的人
     *
     * @param radius 半径,默认 1000m
     * @param lon    经度
     * @param lat    纬度
     * @return
     */
    public List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat) {
        // 获取登录用户信息
        User user = this.getLoginUser();
        int userId = user.getId();

        // 处理半径,默认 1000m
        if (radius == null) {
            radius = 1000;
        }

        // 获取用户经纬度
        Point point = null;
        if (lon == null || lat == null) {
            // 如果经纬度没传,那么从 Redis 中获取
            List<Point> points = redisTemplate.opsForGeo().position(USER_LOCATION_KEY, userId);
            if (points == null || points.isEmpty()) {
                throw new RuntimeException("获取经纬度失败");
            }
            point = points.get(0);
        } else {
            point = new Point(lon, lat);
        }

        // 初始化距离对象,单位 m
        Distance distance = new Distance(radius, RedisGeoCommands.DistanceUnit.METERS);
        // 初始化 Geo 命令参数对象
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        // 附近的人限制3,包含距离,按由近到远排序
        args.limit(3).includeDistance().sortAscending();
        // 以用户经纬度为圆心,范围 1000m
        Circle circle = new Circle(point, distance);
        // 获取附近的人 GeoLocation 信息
        GeoResults<RedisGeoCommands.GeoLocation<Object>> geoResult = redisTemplate.opsForGeo().radius(USER_LOCATION_KEY, circle, args);

        // 构建有序 Map
        Map<Integer, NearMeUserVO> nearMeUserVOMap = Maps.newLinkedHashMap();
        // 完善用户信息
        geoResult.forEach(result -> {
            RedisGeoCommands.GeoLocation<Object> geoLocation = result.getContent();
            // 初始化Vo对象
            NearMeUserVO nearMeUserVO = new NearMeUserVO();
            nearMeUserVO.setId((Integer) geoLocation.getName());
            // 获取距离
            Double dist = result.getDistance().getValue();
            // 四舍五入精确到小数点后 1 位,方便客户端显示
            String distanceStr = NumberUtil.round(dist, 1).toString() + "m";
            nearMeUserVO.setDistance(distanceStr);
            nearMeUserVOMap.put((Integer) geoLocation.getName(), nearMeUserVO);
        });


        // 附近的人,可进一步完善用户信息
//        Integer[] userIds = nearMeUserVOMap.keySet().toArray(new Integer[0]);
        
        ArrayList<NearMeUserVO> nearMeUserVO = Lists.newArrayList(nearMeUserVOMap.values());

        return nearMeUserVO;
    }

    /**
     * 模拟获取真实登录用户信息
     *
     * @return
     */
    public User getLoginUser() {
        User user = new User();
        user.setId(1);
        return user;
    }
}

执行测试

访问执行添加用户地理位置数据接口,得到如下所示数据:

在这里插入图片描述
访问执行获取附近人接口,得到如下所示数据:

	"data": [
		{
			"id": 1,
			"distance": "0.0m"
		},
		{
			"id": 3,
			"distance": "949.3m"
		},
		{
			"id": 2,
			"distance": "1462.2m"
		}
	]

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

湖南大学CS-2020期末考试解析

【特别注意】 答案来源于@wolf 是我在备考时自己做的,仅供参考,若有不同的地方欢迎讨论。 【试卷评析】 有必要一做。 【试卷与答案】 1.简答题(10 分) 假设一个基于 IEEE 浮点格式的 10 位浮点表示,有 1 个符号位,4 个阶码位(k=4)和 5 个 尾数位(n=5)。 (…

湖南大学CS-2018期末考试解析

【特别注意】 答案来源于@wolf 是我在备考时自己做的,仅供参考,若有不同的地方欢迎讨论。 【试卷评析】 有必要一做。 【试卷与答案】 一、选择题(每题 2 分,共 10 分) 1. 0x12345678 存放在采用小端存储的机器上,地址为 0x100 到

湖南大学CS-2017(另一张)期末考试解析

【特别注意】 答案来源于wolf 是我在备考时自己做的&#xff0c;仅供参考&#xff0c;若有不同的地方欢迎讨论。 【试卷评析】 有必要一做。 【试卷与答案】 由于这张试卷没有电子版&#xff0c;我就直接拍我自己的作答了

八大排序算法之归并排序(递归实现+非递归实现)

目录 一.归并排序的基本思想 归并排序算法思想(排升序为例) 二.两个有序子序列(同一个数组中)的归并(排升序) 两个有序序列归并操作代码: 三.归并排序的递归实现 递归归并排序的实现:(后序遍历递归) 递归函数抽象分析: 四.非递归归并排序的实现 1.非递归归并排序算法…

C:\Users\BC>conda -V ‘conda‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

C:\Users\BC>conda -V ‘conda’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 注意&#xff01;&#xff1a;Anaconda安装路径和Scripts路径&#xff0c;两个都添加进去Path 解释&#xff1a;将 Anaconda 安装路径和 Scripts 路径都添加到系统的 PA…

css属性计算过程

CSS 属性计算过程 你是否了解 CSS 的属性计算过程呢&#xff1f; 有的同学可能会讲&#xff0c;CSS属性我倒是知道&#xff0c;例如&#xff1a; p{color : red; }上面的 CSS 代码中&#xff0c;p 是元素选择器&#xff0c;color 就是其中的一个 CSS 属性。 但是要说 CSS 属…

丢失d3dcompiler47.dll怎么办,这个五个修复方法都可以解决

打开游戏或者软件的时候&#xff0c;电脑提示由于找不到d3dcompiler_47.dll&#xff0c;无法继续执行此代码怎么办&#xff0c;其实修复起来不难。首先需要先知道怎么是dll文件&#xff0c;dll文件可以简单的把库文件看成一种代码仓库&#xff0c;它提供给使用者一些可以直接拿…

【学习笔记】Spring Cloud

1、Spring Cloud简介&#xff1a; 成熟的微服务框架&#xff0c;定位为开发人员提供工具&#xff0c;以快速构建分布式系统 2、Spring Cloud核心组件 服务注册中心&#xff1a;Spring Cloud Netflix Eureka&#xff0c;会启动一个Eureka Serve&#xff0c;把其他的组件作为E…

Git分布式版本控制系统

Githttps://git-scm.com/ 1. Git简介 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。分布式相比于集中式的最大区别在于开发者可以提交到本地&#xff0c;每个开发者通过克隆&#xff08;git clone&#xff09;&#xff…

梳理Retrofit的知识体系

作者&#xff1a;RainyJiang 在学习Retrofit后&#xff0c;由于它本身就是OKHttp的封装&#xff0c;面试中也经常会被一起问到&#xff1b;单纯的解析它的源码学习难免会有点无从下手&#xff0c;往往让人抓不住重点&#xff0c;学习效率并不是很高&#xff0c;本文从提出几个问…

我的创作纪念日 2048 AI 面试 Java GoLang

《突击面试》 《面试1v1》 机缘 提示&#xff1a;可以和大家分享最初成为创作者的初心 例如&#xff1a; 实战项目中的经验分享日常学习过程中的记录通过文章进行技术交流… 收获 提示&#xff1a;在创作的过程中都有哪些收获 例如&#xff1a; 获得了多少粉丝的关注获得…

VMware Workstation 11 安装教程

哈喽&#xff0c;大家好。今天一起学习的是VMware Workstation 11的安装&#xff0c;vm虚拟机是小编非常喜欢的生产力软件&#xff0c;小编之前发布的测试教程钧在vm上进行的实验。 VMware Workstation是一款功能强大的桌面虚拟计算机软件&#xff0c;它能够让用户在宿主机操作…

轻松搞定邮件营销!这些工具可以助你提升转化率

据可靠数据统计&#xff0c;邮件营销得投资回报比达1&#xff1a;44&#xff0c;他高性价比的特性在众多营销方式中脱颖而出。他促使企业能够以较低的成本&#xff0c;和客户建立联系并维持长期联系。邮件营销对企业来讲无疑是极佳的获客渠道和营销方式。 想要做好邮件营销通常…

【Java基础学习打卡04】计算机操作系统

目录 引言一、操作系统基本概念二、Windows操作系统三、进程与线程1.进程2.线程 四、CPU与内存总结 引言 了解操作系统基本概念&#xff0c;熟悉Windows操作系统&#xff0c;理解进程与线程概念&#xff0c;并知晓CPU与内存如何工作。 一、操作系统基本概念 计算机操作系统&a…

使用Scala集成开发环境

一、搭建Scala的IntelliJ IDEA开发环境 &#xff08;一&#xff09;启动IDEA &#xff08;二&#xff09;安装Scala插件 启动IDEA&#xff0c;在欢迎界面中选择Configure→Plugins命令 在上方的搜索框中搜索scala关键字 单击绿色的【Install】按钮&#xff0c;安装完毕&am…

Ubuntu20.04 + 3090 安装nvidia驱动,附加解决重启黑屏卡在 /dev/***: clean, **files,***blocks的问题

目录 准备禁用nouveau解决黑屏问题并安装驱动参考 准备 首先需要知道当前电脑/服务器的显卡型号&#xff0c;这个自行查找自己电脑配置 查找显卡对应的驱动版本 通过命令ubuntu-drivers devices查看当前设备所支持的驱动&#xff0c;带有recommended的驱动为推荐安装的版本 不…

【K8S 从0到1实战】Kubernetes一主多从部署实战指南

目录 前言前置准备安装虚拟机关闭防火墙禁用 SELinux关闭 Swap 分区时区设置和时间同步主机名和域名解析配置转发 IPv4 并让 iptables 看到桥接流量 Docker 安装cri-docker 安装Kubernetes 部署配置 Kubernetes 镜像源Kubernetes 组件安装Master 节点初始化Node 节点加入集群…

基于Ti_AWR2243级联板的发射端波束形成(相控阵)的实践

说明 Ti的级联板功能十分强大&#xff0c;用这块板子做TDM(时分)的发射以及TDM发射模式下的数据处理可能更为大家所熟知&#xff0c;但其实因为AWR2243芯片在每个发射链路上有6bit的移相器&#xff0c;再加上板子上有9个发射天线是排布在同一个水平线上的&#xff0c;所以也可以…

万物的算法日记|第二天

笔者自述&#xff1a; 一直有一个声音也一直能听到身边的大佬经常说&#xff0c;要把算法学习搞好&#xff0c;一定要重视平时的算法学习&#xff0c;虽然每天也在学算法&#xff0c;但是感觉自己一直在假装努力表面功夫骗了自己&#xff0c;没有规划好自己的算法学习和总结&am…

JavaSE进阶——玩转IO流

文章目录 前言一、File类介绍1、概念引入2、实际应用2.1 操作文件2.2 操作文件夹 二、IO流介绍三、字符流1、读文件1.1 一次读一个1.2 一次读多个&#xff0c;使用char数组去装 2、写文件2.1 一次写一个2.2 一次写完&#xff0c;使用字符数组 3、文件复制3.1 综合应用3.2 使用缓…