使用 Redis GEO 储存地理位置

Note

本文摘录自《Redis使用手册》, 详情请见: RedisGuide.com

很多社交网站都提供了与地理位置相关的功能, 比如记录用户自己的位置、获取指定用户的位置, 又或者查找指定范围内的其他用户等等。

在学习了 GEOADDGEOPOSGEODIST 这三个命令之后, 我们同样可以构建出一个具有基本功能的用户地理位置程序, 该程序能够记录用户所在的位置、获取指定用户所在的位置以及计算两个用户之间的直线距离, 具体的实现如代码清单 9-1 所示。

代码清单 9-1 具有基本功能的用户地理位置程序: /geo/location.py

import random

USER_LOCATION_KEY = "user_locations"

class Location:

    def __init__(self, client):
        self.client = client
        self.key = USER_LOCATION_KEY

    def pin(self, user, longitude, latitude):
        """
        记录指定用户的坐标。
        """
        self.client.geoadd(self.key, longitude, latitude, user)

    def get(self, user):
        """
        获取指定用户的坐标。
        """
        position_list = self.client.geopos(self.key, user)
        # geopos() 允许用户输入多个位置,然后以列表形式返回各个位置的坐标。
        # 因为我们这里只传入了一个位置,所以只需要取出列表的第一个元素即可。
        if len(position_list) != 0:
            return position_list[0]

    def calculate_distance(self, user_a, user_b):
        """
        以公里为单位,计算两个用户之间的直线距离。
        """
        return self.client.geodist(self.key, user_a, user_b, unit="km")

这个程序所做的就是使用 GEOADD 命令把用户的 ID 以及用户所在的经纬度关联起来, 然后使用 GEOPOS 命令去获取用户所在的经纬度, 又或者使用 GEODIST 命令去计算两个用户之间的直线距离。

通过执行以下代码, 我们可以创建出相应的用户位置对象, 并使用它记录 peter 、jack 和 tom 这三个用户的地理位置:

>>> from redis import Redis
>>> from location import Location
>>> client = Redis(decode_responses=True)
>>> location = Location(client)
>>> location.pin("peter", 113.20996731519699, 23.593675019671288)
>>> location.pin("jack", 113.22784155607224, 23.125598202060807)
>>> location.pin("tom", 113.40603142976761, 22.511156445825442)

然后通过执行以下代码, 获取 peter 和 jack 的坐标:

>>> location.get("peter")
(113.20996731519699, 23.593675019671288)
>>> location.get("jack")
(113.22784155607224, 23.125598202060807)

最后通过执行以下代码, 计算 peter 和 jack 之间的直线距离, 以及 peter 和 tom 之间的直线距离:

>>> location.calculate_distance("peter", "jack")
52.0944
>>> location.calculate_distance("peter", "tom")
122.0651