如何在附近 100w 的商户中,快速找到离你最近的 5 家商户?

Sherwin.Wei Lv7

如何在附近 100w 的商户中,快速找到离你最近的 5 家商户?

回答重点

可以使用 MySQL 或 MongoDB 的空间索引,或者使用 Redis 提供的 Geo 数据结构来存储商户位置的位置信息来实现根据距离的快速查找。

使用空间索引

例如 R-tree,它适用于二维空间的树形数据结构,能够高效地进行范围查询和最近邻查询。将商户位置(经纬度)数据按照地理区域组织成树结构,可以快速找到位于用户当前位置附近。

像 MySQL 就支持 R-tree,或者使用 MongoDB 也支持空间索引。

拿 MongoDB 距离,实现步骤就是:

1)创建一个地理集合

2)将商家的经纬度导入到集合中

1
2
3
4
[{name:"商家A", location:{ type:"Point", coordinates:[111,22]}},
{name:"商家B", location:{ type:"Point", coordinates:[22,77]}}
....
]

3)创建地理索引

给 location 创建 2dsphere 索引

4)根据自己的坐标,利用 $near 查询附近距离

1
2
3
4
5
6
7
8
9
10
11
{
location: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ <我的经度> , <我的维度> ]
},
$maxDistance: <distance in meters> //最大距离,单位米
}
}
}

这里已经自动按最近的排序了,再结合 .limit(20) 即可得到最近的 20家饭店。

使用 Redis 的 Geospatial

Redis 内部使用 Geohash 算法将地理坐标编码为字符串的技术,通过将地球表面划分成网格,来减少坐标的存储空间,并且能够根据前缀进行范围搜索实现快速的区域范围搜索。

1)数据存储:

使用 Redis 的 GEOADD 命令,将饭店的地理位置信息存储在 Redis 中。每个饭店的经纬度信息作为空间坐标进行存储,并关联到饭店的唯一标识符。

1
2
3
GEOADD restaurants:locations longitude1 latitude1 restaurant_id1
GEOADD restaurants:locations longitude2 latitude2 restaurant_id2
...

2)查询附近的饭店:

使用 GEORADIUS命令,根据用户当前位置(经纬度)查询指定半径内的饭店,并按距离排序,返回最接近的 20 家饭店。

1
GEORADIUS restaurants:locations user_longitude user_latitude radius km WITHDISTANCE COUNT 20 ASC
  • user_longitude 和 user_latitude 是用户的经纬度。
  • radius 是查询的半径,单位可以是 m(米)、km(千米)等。
  • WITHDISTANCE 返回与用户的距离。
  • COUNT 20 ASC 返回距离最近的前 20 个结果,并按距离升序排列。

扩展知识

Comments