问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Redis中的GEO类型是什么?如何基于Redis进行地理位置存储与查询

创作时间:
作者:
@小白创作中心

Redis中的GEO类型是什么?如何基于Redis进行地理位置存储与查询

引用
CSDN
1.
https://m.blog.csdn.net/qq_42581023/article/details/144810359

Redis中的GEO类型是一种用于存储地理位置数据的特殊数据结构,支持快速查找指定范围内的所有点、高效计算两个位置之间的距离等操作。本文将详细介绍Redis GEO类型的基本概念、常用操作,并通过网约车场景举例说明其应用场景。

什么是GEO

Redis中的Geo类型是用于存储地理位置数据的特殊数据结构。它允许你存储地理坐标(经纬度)并对这些坐标执行各种操作,如计算距离、查找附近的位置等。Geo类型是在Redis 3.2版本中引入的。

Geo类型在Redis中是基于有序集合(Sorted Set)实现的。它使用Geohash编码将经纬度转换为可以排序的字符串,然后存储为有序集合中的分数。这样就可以利用有序集合的特性来实现地理位置相关的操作。至于Geohash是什么,后续将会形成一片文章来对其做具体介绍,现在你只需要明白,Redis中的Geo类型能够进行计算距离、查找附近的位置等功能即可。

GEO的常用操作

  1. GEOADD
  • 用于将地理空间位置(经纬度)添加到指定的key中。
  • 语法:
    GEOADD key longitude latitude member [longitude latitude member ...]
    
  • 示例:
    GEOADD cities 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
    
  1. GEOPOS
  • 返回指定成员的经纬度(可以有多个)。
  • 语法:
    GEOPOS key member [member ...]
    
  • 示例:
    GEOPOS cities "Palermo" "Catania"
    
  1. GEODIST
  • 计算两个成员之间的距离,可以指定返回的单位(米、千米、英里、英尺)。
  • 语法:
    GEODIST key member1 member2 [unit]
    
  • 示例:
    GEODIST cities "Palermo" "Catania" km
    
  1. GEORADIUS
  • 查找位于指定圆心和半径范围内的所有成员。返回的结果可以按距离排序,并可以选择返回距离或地理位置。
  • 语法:
    GEORADIUS key longitude latitude radius unit [WITHDIST] [WITHCOORD] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
    
  • 示例:
    GEORADIUS cities 15 37 200 km WITHDIST
    
  1. GEORADIUSBYMEMBER
  • 类似于GEORADIUS,但圆心是由给定的成员来指定的。
  • 语法:
    GEORADIUSBYMEMBER key member radius unit [WITHDIST] [WITHCOORD] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
    
  • 示例:
    GEORADIUSBYMEMBER cities "Palermo" 100 km
    
  1. GEOHASH
  • 返回一个或多个成员的Geohash表示。
  • 语法:
    GEOHASH key member [member ...]
    
  • 示例:
    GEOHASH cities "Palermo" "Catania"
    

场景举例

我们以网约车场景举例来说明GEO类型常用的操作,这个场景里有两位司机分别为张师傅和王师傅,以及一位打车的小王同学。

三个人的空间位置关系如图所示:

其对应的GeoJson数据如下:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "driver": "张师傅"
      },
      "geometry": {
        "coordinates": [
          116.3308032723209,
          39.94238054837655
        ],
        "type": "Point"
      },
      "id": 0
    },
    {
      "type": "Feature",
      "properties": {
        "driver": "李师傅"
      },
      "geometry": {
        "coordinates": [
          116.39043340452554,
          39.925354295445146
        ],
        "type": "Point"
      },
      "id": 1
    },
    {
      "type": "Feature",
      "properties": {
        "user": "小王",
        "marker-color": "#e30202",
        "marker-size": "medium",
        "marker-symbol": "circle"
      },
      "geometry": {
        "coordinates": [
          116.35007287314164,
          39.922752082291424
        ],
        "type": "Point"
      },
      "id": 2
    }
  ]
}

Java代码示例

使用Jedis作为操作Redis的客户端。

class RedisGeo{
    @Test  
    public void geoBaseApi(){  
        String DRIVERS_REDIS_KEY = "drivers";  
        // 添加师傅所在位置  
        jedis.geoadd(DRIVERS_REDIS_KEY,116.3308032723209 ,39.94238054837655,"张师傅");  
        jedis.geoadd(DRIVERS_REDIS_KEY,116.39043340452554 ,39.925354295445146,"王师傅");  
        // 小王同学所在位置经纬度  
        Double userWangLng = 116.35007287314164;  
        Double userWangLat = 39.922752082291424;  
        // 查询张师傅所在位置,可同时查询多个member的位置,所以返回值为List  
        List<GeoCoordinate> geoposOfZhang = jedis.geopos(DRIVERS_REDIS_KEY, "张师傅");  
        for (GeoCoordinate geoCoordinate : geoposOfZhang) {  
            log.info("张师傅所在位置,经度:{},纬度:{}",geoCoordinate.getLongitude(),geoCoordinate.getLatitude());  
        }  
        // 计算张师傅和王师傅之间的距离,GeoUnit 不赋值,默认为米  
        Double geodist = jedis.geodist(DRIVERS_REDIS_KEY, "张师傅", "王师傅",GeoUnit.KM);  
        log.info("张师傅和王师傅的距离为:{}KM",geodist);  
        // 查找小王同学附近的司机  
        List<GeoRadiusResponse> drivers = jedis.georadius(DRIVERS_REDIS_KEY, userWangLng, userWangLat, 5, GeoUnit.KM, GeoRadiusParam.geoRadiusParam().withDist());  
        for (GeoRadiusResponse geoRadiusResponse : drivers) {  
            log.info("小王同学附近有司机:{},距离小王同学的距离为:{}KM",geoRadiusResponse.getMemberByString(),geoRadiusResponse.getDistance());  
        }  
        // 以王师傅为中心,查找王师傅附近5KM的司机  
        List<GeoRadiusResponse> nearbyDrivers = jedis.georadiusByMember(DRIVERS_REDIS_KEY, "王师傅", 5, GeoUnit.KM,GeoRadiusParam.geoRadiusParam().withDist());  
        for (GeoRadiusResponse geoRadiusResponse : drivers) {  
            log.info("王师傅附近的司机:{},距离王师傅的距离为:{}KM",geoRadiusResponse.getMemberByString(),geoRadiusResponse.getDistance());  
        }  
    }
}

一些类的介绍

GeoRadiusParam

在上述示例代码中,有这样的一行代码:

// 查找小王同学附近的司机  
List<GeoRadiusResponse> drivers = jedis.georadius(DRIVERS_REDIS_KEY, userWangLng, userWangLat, 5, GeoUnit.KM, GeoRadiusParam.geoRadiusParam().withDist()); 

这里的参数GeoRadiusParam.geoRadiusParam().withDist()的作用就是返回距离相关信息。在使用 Redis 的 Geo 命令时,GEORADIUSGEORADIUSBYMEMBER支持多种选项来定制查询结果。如果你没有明确要求返回距离信息,默认情况下,GeoRadiusResponse中的距离会返回为 0。

GeoRadiusParam是一个辅助类,用于构建GEORADIUSGEORADIUSBYMEMBER命令的参数。这使得查询更加灵活和可定制。

常用方法

  • withDist():指定返回结果中包含距离。
  • withCoord():指定返回结果中包含坐标。
  • sortAscending():按距离升序排序结果。
  • sortDescending():按距离降序排序结果。
  • count(int count):限制返回结果的数量。

GeoRadiusResponse

GeoRadiusResponse是一个类,用于封装GEORADIUSGEORADIUSBYMEMBER命令的结果。每个GeoRadiusResponse实例代表一个查询结果。

主要方法

  • getMemberByString():返回成员名称,作为字符串。
  • getDistance():返回距离(如果查询中包含WITHDIST)。
  • getCoordinate():返回坐标(如果查询中包含WITHCOORD)。

本文原文来自CSDN

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号