基于 Redis 实现的附近车辆查询功能
前言
随着移动互联网的快速发展,移动互联网已覆盖我们生活的方方面面!
日常生活中,我们所使用的外卖、打车、附近商家等功能是如何实现的呢?
比如:
- 外卖:如何根据用户的当前位置找到附近的商家?
- 打车:当用户需要打车时,系统如何安排距离较近的车辆?
- 社交:微信“附近的人”、陌陌、探探等交友功能是如何实现的?
了解这些功能的实现原理后,我们可以通过 Redis 的 geo 特性轻松实现类似功能!
Redis 的 Geo 特性简介
通过 Redis 的 geo 特性,我们可以存储用户上报的经纬度信息,并基于这些信息进行距离计算等操作。
Redis 3.2 版本引入了 geo 特性,因此要使用该功能,需要将 Redis 版本升级至 3.2 及以上。
实现步骤
第一步:用户坐标信息上报
在移动端获取 GPS 权限后,设备定时向服务器上报当前的经纬度信息。
例如:滴滴打车的车辆会定时上报当前车辆的经纬度信息。
服务器通过 Redis 的 geo 特性将这些坐标信息存储在 Redis 中。
命令参考
GEOADD key longitude latitude member
将某一地点(经纬度坐标)存入 Redis。
示例代码
<?php
$redis = new \Redis();
$redis->connect('redis', 6379);
// 向 "carlist" 集合中增加两个车辆(car1、car2)的经纬度坐标
$redis->geoadd('carlist', '-100.6331263694', '40.2054986348', 'car1');
$redis->geoadd('carlist', '-100.6306533726', '40.2047529787', 'car2');
执行结果:将两个车辆的坐标成功存储到 Redis 中。
第二步:根据用户当前坐标查询附近车辆
当用户请求打车时,系统会接收到用户的当前坐标。
系统将根据该坐标,在指定范围内(如 5 公里)查找距离用户较近的车辆。
命令参考
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count]
根据指定的经纬度坐标,查询指定半径范围内的所有元素。
示例代码
<?php
$redis = new \Redis();
$redis->connect('redis', 6379);
// 查询距离用户坐标(-100.6301598462, 40.2067989295)5 公里范围内的车辆
// 返回结果包含车辆的距离和坐标,并按距离由近及远排序
$carlist = $redis->georadius('carlist', '-100.6301598462', '40.2067989295', 5, 'km', ['WITHDIST', 'WITHCOORD', 'ASC']);
var_dump($carlist);
执行结果:
array(2) {
[0]=>
array(3) {
[0]=>
string(4) "car2"
[1]=>
string(6) "0.2315" // 距离(公里)
[2]=>
array(2) {
[0]=>
string(22) "-100.63065379858016968" // 车辆的经度
[1]=>
string(20) "40.20475215137940239" // 车辆的纬度
}
}
[1]=>
array(3) {
[0]=>
string(4) "car1"
[1]=>
string(6) "0.2905" // 距离(公里)
[2]=>
array(2) {
[0]=>
string(22) "-100.63312679529190063" // 车辆的经度
[1]=>
string(20) "40.20549989412140945" // 车辆的纬度
}
}
}
附言
在实际项目中,用户或车辆的位置可以通过长连接协议(如 WebSocket)实时上报到服务器。
基于 GEORADIUS
的灵活参数,我们可以按需返回距离、坐标信息以及排序等。
虽然 MySQL 相关函数也可以实现类似功能,但在处理实时地理信息时不推荐使用 MySQL。
MongoDB 和 Elasticsearch 也提供了强大的地理位置查询功能,具体实现可以参考相关文档。
Redis Geo 其他命令
更多 Redis Geo 命令及用法请参考官方文档:Geo 命令文档