Redis中的GEO类型是什么?如何基于Redis进行地理位置存储与查询
Redis中的GEO类型是什么?如何基于Redis进行地理位置存储与查询
Redis中的GEO类型是一种用于存储地理位置数据的特殊数据结构,支持快速查找指定范围内的所有点、高效计算两个位置之间的距离等操作。本文将详细介绍Redis GEO类型的基本概念、常用操作,并通过网约车场景举例说明其应用场景。
什么是GEO
Redis中的Geo类型是用于存储地理位置数据的特殊数据结构。它允许你存储地理坐标(经纬度)并对这些坐标执行各种操作,如计算距离、查找附近的位置等。Geo类型是在Redis 3.2版本中引入的。
Geo类型在Redis中是基于有序集合(Sorted Set)实现的。它使用Geohash编码将经纬度转换为可以排序的字符串,然后存储为有序集合中的分数。这样就可以利用有序集合的特性来实现地理位置相关的操作。至于Geohash是什么,后续将会形成一片文章来对其做具体介绍,现在你只需要明白,Redis中的Geo类型能够进行计算距离、查找附近的位置等功能即可。
GEO的常用操作
- GEOADD
- 用于将地理空间位置(经纬度)添加到指定的key中。
- 语法:
GEOADD key longitude latitude member [longitude latitude member ...]
- 示例:
GEOADD cities 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
- GEOPOS
- 返回指定成员的经纬度(可以有多个)。
- 语法:
GEOPOS key member [member ...]
- 示例:
GEOPOS cities "Palermo" "Catania"
- GEODIST
- 计算两个成员之间的距离,可以指定返回的单位(米、千米、英里、英尺)。
- 语法:
GEODIST key member1 member2 [unit]
- 示例:
GEODIST cities "Palermo" "Catania" km
- 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
- GEORADIUSBYMEMBER
- 类似于GEORADIUS,但圆心是由给定的成员来指定的。
- 语法:
GEORADIUSBYMEMBER key member radius unit [WITHDIST] [WITHCOORD] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
- 示例:
GEORADIUSBYMEMBER cities "Palermo" 100 km
- 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 命令时,GEORADIUS
和GEORADIUSBYMEMBER
支持多种选项来定制查询结果。如果你没有明确要求返回距离信息,默认情况下,GeoRadiusResponse
中的距离会返回为 0。
GeoRadiusParam
是一个辅助类,用于构建GEORADIUS
和GEORADIUSBYMEMBER
命令的参数。这使得查询更加灵活和可定制。
常用方法:
withDist()
:指定返回结果中包含距离。withCoord()
:指定返回结果中包含坐标。sortAscending()
:按距离升序排序结果。sortDescending()
:按距离降序排序结果。count(int count)
:限制返回结果的数量。
GeoRadiusResponse
GeoRadiusResponse
是一个类,用于封装GEORADIUS
和GEORADIUSBYMEMBER
命令的结果。每个GeoRadiusResponse
实例代表一个查询结果。
主要方法:
getMemberByString()
:返回成员名称,作为字符串。getDistance()
:返回距离(如果查询中包含WITHDIST
)。getCoordinate()
:返回坐标(如果查询中包含WITHCOORD
)。
本文原文来自CSDN