Redis:GEO应用

本文介绍了Redis数据类型GEO的相关概念、命令推荐使用场景应用代码举例

目录

GEO:概念与相关命令

概念

命令

推荐使用场景

应用代码举例


GEO:概念与相关命令

概念

GEO可以理解为是一种特殊的Zset,只是其分数值由经度和纬度共同决定。

GEO常用于地理位置相关的操作,如计算两点之间的距离、查找附近的成员等。

粗略技术原理:geoadd 命令 -- Redis中国用户组(CRUG),更详细的内容可自行了解。

命令

  1. GEOADD:将一个或多个成员的地理位置添加到指定的GEO数据结构中。
  2. GEODIST:计算两个成员之间的地理距离。
  3. GEOPOS:获取一个或多个成员的地理位置坐标。
  4. GEORADIUS:根据给定的地理位置和半径范围,查找附近的成员。
  5. GEORADIUSBYMEMBER:根据给定的成员和半径范围,查找附近的成员。
  6. GEOREMOVE:从GEO数据结构中移除一个或多个成员。
  7. GEORADIUS_WITHDIST:查找附近的成员,并返回距离信息。
  8. GEORADIUS_WITHCOORD:查找附近的成员,并返回坐标信息。

(仅列出常用命令,其他命令可自行到官网Commands | Redis查看)

推荐使用场景

地理位置相关的功能主要可归类为这两类:

  • 地理位置服务:
    • 构建地图:如定位服务、附近的商店和酒店、美团找单车等。实现思路:将所有的商店存入key为商店的geo,将酒店存入key为商店的geo,将单车位置存入key为单车的geo,当需要获得指定半径内的对应物品时,就使用GEORADIUS命令指定自己位置、半径以及需要查询的key,即可获得对应的其他所需物品位置。
    • 位置分析:如根据地图进行路线生成、寻找热门商业圈等。实现思路:导航功能一般是直接调用高德地图、百度地图这类api进行导航...导航功能需要坐标点数据(起点、终点坐标、途经点坐标)和道路数据(道路网络连接关系、路段信息、交通信息),通常需要使用图数据结构和路径规划算法(如Dijkstra、A*、或者基于实时交通的算法),往往无法单纯使用GEO实现,GEO仅能提供一些辅助功能如根据位置远近推荐目的地。
  • 轨迹追踪:
    • 位置跟踪:如外卖员位置和预计到达时间等。实现思路:实时获得更新自己、对方位置,获得之间距离;同时配合道路数据进行剩余时间计算。
    • 地理围栏:借助位置跟踪,当某个对象进入或离开指定区域时触发事件。实现思路:实时更新位置,当目标与目的地达到一定距离以内或以外则触发事件。

应用代码举例

建议使用管道输入中国大多数城市的坐标,坐标文件已绑定。

此处仅演示各类命令使用:(建议使用StringRadisTemplate,避免序列化问题)

package com.example.redis_study.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @auther 齿轮
 * @create 2023-09-05-20:36
 */
@RestController
public class GEOController {
    public static final String key = "china";
    @Autowired
    StringRedisTemplate redisTemplate;

    //GEOADD
    @PostMapping("/GEOADD")
    public void AddCity(@RequestParam double longitude, @RequestParam double latitude, @RequestParam String city) {
        Map<String, Point> map = new HashMap<>();
        map.put(city, new Point(longitude, latitude));
        System.out.println(map);
        redisTemplate.opsForGeo().add(key, map);
    }

    //GEOOPS
    @GetMapping("/GEOOPS")
    public String getCity(@RequestParam String city) {
        List position = redisTemplate.opsForGeo().position(key, city);
        return position.toString();
    }

    //GEODIST
    @GetMapping("/GEODIST")
    public String getDist(@RequestParam String city1, @RequestParam String city2) {
        Distance distance = redisTemplate.opsForGeo().distance(key, city1, city2, Metrics.KILOMETERS);
        return distance.toString();
    }

    //GEORADIUS
    @GetMapping("/GEORADIUS")
    public Object getCitiesByRadius(@RequestParam double longitude, @RequestParam double latitude, @RequestParam double radius, @RequestParam int count) {

        Circle circle = new Circle(new Point(longitude, latitude), new Distance(radius, Metrics.KILOMETERS));//指定自己坐标
        //设置返回条件
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().
                includeDistance().
                includeCoordinates().
                sortAscending().
                limit(count);
        //获得返回结果
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(key, circle, args);
        return results;
    }

    //GEORADIUSBYMEMBER
    @GetMapping("/GEORADIUSBYMEMBER")
    public Object getCitiesByRadiusAndOtherCity(@RequestParam String city, @RequestParam double radius, @RequestParam int count) {
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().
                includeDistance().
                includeCoordinates().
                sortAscending().
                limit(count);
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(key, city, new Distance(radius, Metrics.KILOMETERS), args);
        return results;
    }
}

运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值