5. Redis GEO

24 篇文章 0 订阅

GEO简介:

  • 目前软件中附近的人是怎么实现的呢?
    1. 使用SQL : select taxi from position where x0-r < x < x0 + r and y0-r < y < y0+r

但是这样会有什么问题呢?
1.查询性能问题,如果并发高,数据量大这种查询是要搞垮数据库的
2.这个查询的是一个矩形访问,而不是以我为中心r公里为半径的圆形访问。
3.精准度的问题,我们知道地球不是平面坐标系,而是一个圆球,这种矩形计算在长距离计算时会有很大误差

    1. 使用Redis GEO

原理:

  1. 将三维的地球变为二维的坐标
  2. 在将二维的坐标转换为一维的点块
  3. 最后将一维的点块转换为二进制再通过base32编码

命令

  1. geoadd添加经纬度坐标
    在这里插入图片描述
    在这里插入图片描述

  2. GEOPOS 返回经纬度
    在这里插入图片描述
    在这里插入图片描述

  3. GEOHASH返回坐标的geohash表示:
    在这里插入图片描述
    在这里插入图片描述
    geohash算法生成的base32编码值,3维变2维变1维

  4. GEODIST 两个位置之间距离:
    在这里插入图片描述
    在这里插入图片描述

  5. GEORADIUS:
    georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
    GEORADIUS city 116.418017 39.914402 10 km withdist withcoord count 10 withhash desc

  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大
  • COUNT 限定返回的记录数。
    在这里插入图片描述
  1. GEORADIUSBYMEMBER
  • 找出指定范围内的元素
    在这里插入图片描述

    @RestController
    public class GeoController
    {
    public static final String CITY =“city”;

    @Autowired
    private RedisTemplate redisTemplate;
    
    @RequestMapping("/geoadd")
    public String geoAdd()
    {
        Map<String, Point> map= new HashMap<>();
        map.put("天安门",new Point(116.403963,39.915119));
        map.put("故宫",new Point(116.403414 ,39.924091));
        map.put("长城" ,new Point(116.024067,40.362639));
    
        redisTemplate.opsForGeo().add(CITY,map);
    
        return map.toString();
    }
    
    @GetMapping(value = "/geopos")
    public Point position(String member) {
        //获取经纬度坐标
        List<Point> list= this.redisTemplate.opsForGeo().position(CITY,member);
        return list.get(0);
    }
    
    @GetMapping(value = "/geohash")
    public String hash(String member) {
        //geohash算法生成的base32编码值
        List<String> list= this.redisTemplate.opsForGeo().hash(CITY,member);
        return list.get(0);
    }
    
    @GetMapping(value = "/geodist")
    public Distance distance(String member1, String member2) {
        Distance distance= this.redisTemplate.opsForGeo().distance(CITY,member1,member2, RedisGeoCommands.DistanceUnit.KILOMETERS);
        return distance;
    }
    
    /**
     * 通过经度,纬度查找附近的
     * 北京王府井位置116.418017,39.914402
     */
    @GetMapping(value = "/georadius")
    public GeoResults radiusByxy() {
        //这个坐标是北京王府井位置
        Circle circle = new Circle(116.418017, 39.914402, Metrics.KILOMETERS.getMultiplier());
        //返回50条
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(50);
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults= this.redisTemplate.opsForGeo().radius(CITY,circle, args);
        return geoResults;
    }
    
    /**
     * 通过地方查找附近
     */
    @GetMapping(value = "/georadiusByMember")
    public GeoResults radiusByMember() {
        String member="天安门";
        //返回50条
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(50);
        //半径10公里内
        Distance distance=new Distance(10, Metrics.KILOMETERS);
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults= this.redisTemplate.opsForGeo().radius(CITY,member, distance,args);
        return geoResults;
    }
    

    }

Redis GeoRedis提供的一种地理位置信息存储与查询的工具。通过Redis Geo,用户可以轻易地存储和查询地理位置信息,比如地理坐标、距离计算、范围查询等。 下面是一个Redis Geo工具类的示例代码: ``` import redis from typing import List, Tuple class RedisGeo: def __init__(self, host: str, port: int, db: int): self.redis = redis.Redis(host=host, port=port, db=db) def add_location(self, key: str, longitude: float, latitude: float, member_name: str): self.redis.geoadd(key, longitude, latitude, member_name) def get_location(self, key: str, member_name: str) -> Tuple[float, float]: return self.redis.geopos(key, member_name)[0] def get_distance(self, key: str, member1: str, member2: str, unit: str) -> float: return self.redis.geodist(key, member1, member2, unit=unit) def get_locations_in_radius(self, key: str, longitude: float, latitude: float, radius: float, unit: str) -> List[str]: return self.redis.georadius(key, longitude, latitude, radius, unit=unit, withdist=True, withcoord=False, sortasc=True, count=None) def get_locations_in_box(self, key: str, min_longitude: float, min_latitude: float, max_longitude: float, max_latitude: float) -> List[str]: return self.redis.georadiusbymember(key, member_name, radius, unit=unit, withdist=True, withcoord=False, sortasc=True, count=None) ``` 这个工具类封装了Redis Geo提供的常用操作,包括: - add_location:添加地理位置信息 - get_location:获取地理位置坐标 - get_distance:获取两个地理位置的距离 - get_locations_in_radius:获取某个地理位置周围一定范围内的所有地理位置信息 - get_locations_in_box:获取某个地理位置周围一个矩形范围内的所有地理位置信息 使用时,只需创建一个RedisGeo对象,并调用相应的方法即可,示例如下: ``` redis_geo = RedisGeo(host='127.0.0.1', port=6379, db=0) redis_geo.add_location('cities', 116.4074, 39.9042, 'Beijing') redis_geo.add_location('cities', 121.4737, 31.2304, 'Shanghai') redis_geo.add_location('cities', 113.2644, 23.1291, 'Guangzhou') print(redis_geo.get_location('cities', 'Beijing')) print(redis_geo.get_distance('cities', 'Beijing', 'Shanghai', 'km')) print(redis_geo.get_locations_in_radius('cities', 116.4074, 39.9042, 2000, 'km')) print(redis_geo.get_locations_in_box('cities', 110, 20, 120, 30)) ``` 这段代码将三个城市的地理位置信息存储在名为“cities”的Redis Geo Key中,并通过RedisGeo对象的方法获取了这些地理位置信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值