我在服务器端有一个Python程序,管理用户位置信息,每个朋友都有一对(经度,纬度)坐标,给定一个(经度,纬度)点,如何高效地找到附近的朋友(比如在5公里范围内)?
我有1万个在线用户...
谢谢。 Bin
新回答:
我会将纬度和经度存储在不同的列中,并在它们上面放置索引。然后,当您想要查找特定用户附近的朋友时,只需执行以下操作:
select field1, field1, ..., fieldn from users
where
user_lat > this_lat - phi and user_lat < this_lat + phi
and
user_lon > this_lon - omega and user_lon < this_lon + omega
在这里,phi
和omega
分别代表与所需距离对应的纬度和经度角度。这将根据您所处的地球位置而异,但已经有了确定方程来计算。另外,您的数据库也可以为您完成这些计算。
旧答案。
我相信,kd树是此处的规范解决方案。
一种简单方法是按经度排序这些点,然后在查找朋友时找到可能匹配的最小和最大经度。对该列表进行排序为O(n log n),查找朋友是线性的,但仅限于经度范围内的朋友。这里有一个示例,假设您拥有所有点都在平面2D表面上的情况:
# friends is the sorted list of (x, y) tuples, (px, py) is my location
def get_near(friends, px, py, maxdist):
i1 = bisect.bisect_left(friends, (px - maxdist, py))
i2 = bisect.bisect_right(friends, (px + maxdist, py))
return [(x, y) for (x, y) in friends[i1:i2] if math.hypot(px - x, py - y) < maxdist]
对于经度/纬度的情况,您需要使用另一个函数来测试距离,而不是欧几里得距离(math.hypot)。
http://www.movable-type.co.uk/scripts/latlong.html 就效率而言,唯一想到的就是在数据存入数据库时预先计算距离,即创建另一个表格来存储位置对及其距离,每添加一个位置时,您需要计算它与系统中所有其他点的距离,但随后在该表格上的查找可以快速解决某个距离内的位置。
Aaronasterling 的回答似乎是我自己试图思考但不知道存在的 :) 所以这可能是一个更好的解决方案,但我相信在使用该算法时会产生一些开销(尽管可能很小,因为通常遍历树只要它合理平衡通常是一个相当快速的过程,我还需要一些时间来了解树的组成方式,因为那个是一个新概念对我来说)。