图解Redis 08 | GEO数据类型的原理及应用场景

介绍

在我们的日常生活中,我们越来越依赖于位置服务(Location-Based Service, LBS),例如查找附近的商场、餐厅,或者在出行时使用打车软件。这些服务都离不开精确的地理位置信息。

LBS应用主要是根据目标人物或物体相关的一组经纬度等地理位置信息,然后根据这些经纬度数据查询目标附近的位置。

Redis GEO 就是专门用于存储和操作地理位置信息的数据类型,它是 Redis 3.2 版本新增的功能,提供了高效的方式来处理和查询这些地理位置信息。

内部实现

Redis GEO 直接使用了 Sorted Set 数据结构来实现其功能,而没有设计新的底层数据结构。它通过 GeoHash 编码将经纬度转换为 Sorted Set 中的元素权重分数。这一过程涉及两个关键机制:

  1. 将二维空间划分为区间
  2. 对这些区间进行编码。

具体来说,Redis GEO 首先将地球表面划分为多个区间。每个经纬度点会被映射到一个特定的区间,然后用该区间的编码值作为该点在 Sorted Set 中的权重分数。这样,经纬度信息被转换为有序的权重分数,存储在 Sorted Set 中。

通过这种方式,Redis GEO 能够利用 Sorted Set 的按权重有序范围搜索功能,来实现位置服务中常见的“附近搜索”需求。

关于GeoHash 编码,后面会有文章专门介绍。

常用命令

添加地理位置
geoadd key longitude latitude member [longitude latitude member ...]

# member:位置的唯一标识符,如名称或ID。

此命令支持一次添加一个或多个位置。

查询位置信息
geopos key member [member ...]

此命令支持查看一个或多个位置信息。

距离计算
geodist key member1 member2 [unit]
查询给定经纬度坐标附近的地点
georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]

# longitude:查询点的经度。
# latitude:查询点的纬度。
# radius:查询的半径距离
# m|km|ft|mi:指定距离的单位(ft:英尺, mi:英里)
# WITHCOORD:在返回结果中包含匹配地点的经纬度坐标
# WITHDIST:在返回结果中包含匹配地点与查询点的距离
# WITHHASH:返回用于排序的 52 位 Geohash 值
# COUNT count:限制返回的结果数量。例如,COUNT 5 将返回最近的 5 个地点。
# ASC|DESC:指定结果按距离的升序(ASC)或降序(DESC)排序
查询位置在地理空间中的 Geohash 值
geohash key **member** [**member** ...]
删除地理位置
zrem key member [member ...]

接下来我们通过一个小例子来看看这些命令的使用。

基本使用

1. 添加地理位置

现在我们有三个地址及其对应的经纬度信息:

  • 地铁站:经度 114.16925398121207,纬度 22.31933370421187
  • 酒店:经度 114.16797226485401,纬度 22.318558441758913
  • 公园:经度 114.16563066766174,纬度 22.31422601342281

接下来,我们可以将这些位置数据添加到 Redis 的 GEO 类型中。通过 Redis GEO,我们能够将经纬度信息存储起来,并使用其强大的查询功能来实现位置相关的操作。

127.0.0.1:6379> geoadd site 114.16934055417407 22.319256344571457 Subway:Station
(integer) 1
127.0.0.1:6379> geoadd site 114.16797226485401 22.318558441758913 Hotel
(integer) 1
127.0.0.1:6379> geoadd site 114.16563066766174 22.31422601342281 Park
(integer) 1
127.0.0.1:6379>
2. 查询位置信息

查看刚刚添加的酒店的地理位置。

127.0.0.1:6379> geopos site Hotel
1 ) 1 ) “114.1679719090461731” 
   2 ) “22.31855819325424051”
3. 距离计算

我们来算一下从酒店到公园的距离是多少米

127.0.0.1:6379> geodist site Hotel Park m
"538.5748"

可以看出,两个位置之间的直接距离为538.5748米。

4. 查询指定经纬度附近范围内的地址信息

我们来查看一下指定经纬度附近范围内的地址信息,假设以酒店的地址作为输入,看看500米以内的结果:

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m
1) "Hotel"
2) "Subway:Station"

可以看到,地铁站距离酒店不到500米。

以下是一些可选参数的解释:

  • WITHCOORD: 在返回结果中包含匹配地点的经纬度坐标

示例:

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m withcoord
1) 1) "Hotel"
   2) 1) "114.1679719090461731"
      2) "22.31855819325424051"
2) 1) "Subway:Station"
   2) 1) "114.16933983564376831"
      2) "22.31925524157305318"
  • WITHDIST: 在返回结果中包含匹配地点与查询点的距离。

示例:

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m withdist
1) 1) "Hotel"
   2) "0.0459"
2) 1) "Subway:Station"
   2) "160.6462"
  • WITHHASH: 返回用于排序的 52 位 Geohash 值

示例:

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m withhash
1) 1) "Hotel"
   2) (integer) 4046428744548977
2) 1) "Subway:Station"
   2) (integer) 4046428745401866
  • COUNT count: 限制返回的结果数量。

示例:

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m count 1
1) "Hotel"

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m count 2
1) "Hotel"
2) "Subway:Station"
  • ASC|DESC: 指定结果按距离的升序(ASC)或降序(DESC)排序
    示例:
127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m desc
1) "Subway:Station"
2) "Hotel"

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m asc
1) "Hotel"
2) "Subway:Station"

当然,上面的可选参数也可以一起使用,比如:

127.0.0.1:6379> georadius site 114.16797226485401 22.318558441758913 500 m withdist desc
1) 1) "Subway:Station"
   2) "160.6462"
2) 1) "Hotel"
   2) "0.0459"
5. 查询指定地址的哈希值
127.0.0.1:6379> geohash site Hotel
1) "wecnvyyx480"

该命令支持查询一个或多个地址的哈希值。

6. 删除地址
127.0.0.1:6379> zrem site Hotel
(integer) 1

//Re-query is null
127.0.0.1:6379> geohash site Hotel
1) (nil)

应用场景

网约出租车

下面我们以网约出租车场景为例介绍如何使用GEO命令实现查找附件的人或附近的出租车等功能。

假设现在有两辆出租车:

  • 车辆 1 的 ID 为 520,其位置的经纬度为 (114.17351602367509, 22.324873810295088)。
  • 车辆 2 的 ID 为 521,其位置的经纬度为 (114.16907428570298, 22.324223743873898)。

我们可以使用一个名为 taxi:locations 的 GEO 集合来保存所有车辆的地理位置信息。

127.0.0.1:6379> geoadd taxi:locations 114.17351602367509 22.324873810295088 520 114.16907428570298 22.324223743873898 521
(integer) 2

当用户想要查找附近的在线出租车时,应用程序可以使用 Redis 的 GEORADIUS 命令来实现这一功能。

例如,当用户发起叫车请求时,应用程序将执行以下命令,Redis 将根据用户提供的经纬度信息 (114.16848419961286, 22.322288413685154) 作为中心点,查找半径 5 公里范围内的所有出租车,并将这些车辆的信息返回给用户:

127.0.0.1:6379> GEORADIUS taxi:locations 114.16848419961286 22.322288413685154 5 km withdist ASC COUNT 5
1) 1) "521"
   2) "0.2235"
2) 1) "520"
   2) "0.5920"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值