使用 redis-py 储存地理位置数据

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:   Redis 3.2 版本的其中一个重要更新就是提供了对地理位置(GEO)数据的支持, 这一特性允许用户将地理位置信息储存到 Redis 数据库中, 并对它们执行距离计算、范围查找等操作。  尽管 Redis 3.2 正式释出已经有一段时间了, 但是 Redis 最常用的 Python 库 redis-py 却一直没有添加对 GEO 特性的支持, 这给使用 Python 操作 Redis 的用户们带来了不少麻烦。  可喜的是, 今天笔者在逛 github 的时候, 发现 redis-py 的最新版本已经添加了对 GEO 特性的支持, 所以今天就让我们一起来看看如何在 redis-p

  Redis 3.2 版本的其中一个重要更新就是提供了对地理位置(GEO)数据的支持, 这一特性允许用户将地理位置信息储存到 Redis 数据库中, 并对它们执行距离计算、范围查找等操作。

  尽管 Redis 3.2 正式释出已经有一段时间了, 但是 Redis 最常用的 Python 库 redis-py 却一直没有添加对 GEO 特性的支持, 这给使用 Python 操作 Redis 的用户们带来了不少麻烦。

  可喜的是, 今天笔者在逛 github 的时候, 发现 redis-py 的最新版本已经添加了对 GEO 特性的支持, 所以今天就让我们一起来看看如何在 redis-py 中处理地理位置数据。

  下载并安装新版 redis-py

  因为支持 GEO 命令的最新版 redis-py 仍处于开发阶段, 所以它无法通过 pypi 取得。 为此, 我们需要从 redis-py 的 github 页面手动克隆最新版本的 redis-py :

  $ git clone git@github:andymccurdy/redis-py.git

  在克隆操作执行完毕之后, 我们进入到 redis-py 文件夹中, 然后将这个新版本安装到系统中:

  $cd redis-py

  $sudo setup.py install

  如果你的系统已经安装了其他版本的 redis-py , 那么记得在安装新版之前, 先将旧版本卸载掉。

  在安装操作执行完毕之后, 我们在解释器中载入 redis-py 库:

  >>> from redis import Redis

  >>> r=Redis()

  通过对 Redis() 对象的属性进行访问, 我们可以确认各个 GEO 命令在 redis-py 中都有了相应的方法:

  >>> for i in dir(r):

  ... if i.startswith("geo"):

  ... print(i)

  ...

  geoadd

  geodist

  geohash

  geopos

  georadius

  georadiusbymember

  接下来, 就让我们逐个试试这些方法。

  添加地理位置

  首先要测试的是 geoadd() 方法, 这个方法调用的是 Redis 的 GEOADD 命令, 它的文档如下:

  geoadd(self, name, *values) method of redis.clientis instance

  Add the specified geospatial items to the specified key identified

  by the name argument. The Geospatial items are given as ordered

  members of the values argument, each item or place is formed b

  the triad latitude, longitude and name.

  作为例子, 以下代码展示了如何使用 geoadd() 方法, 将清远、广州和佛山这三个城市的坐标添加到 "Guangdong" 这个键里面:

  >>> r.geoadd("Guangdong", "113.2099647", "23.593675", "Qingyuan", 113.2278442, 23.1255978, "Guangzhou", 113.106308, 23.0088312, "Foshan")

  3获取地理位置

  在将地理位置储存到键里面之后, 我们就可以使用 GEOPOS 命令去获取已储存的地理位置信息。 在 redis-py 里面, GEOPOS 命令可以通过执行 geopos() 方法来调用, 以下是这一方法的文档:

  geopos(self, name, *values) method of redis.clientis instance

  Return the postitions of each item of values as members of

  the specified key identified by the nameargument. Each position

  is represented by the pairs lat and lon.

  比如说, 以下代码就展示了如何使用 geopos() 方法去从 "Guangdong" 键中获取清远和广州的地理位置:

  >>> r.geopos("Guangdong", "Qingyuan", "Guangzhou")

  [(113.20996731519699, 23.593675019671288), (113.22784155607224, 23.125598202160807)]计算两地间的距离

  对于被储存的两个地理位置, 我们可以使用 GEODIST 命令去计算它们之间的距离, 而这个命令在 redis-py 中可以通过同名的 geodist() 方法去调用, 以下是该方法的文档说明:

  geodist(self, name, place1, place2, unit=None) method of redis.clientis instance

  Return the distance between place1 and place2 members of the

  name key.

  The units must be one o fthe following : m, km mi, ft. By default

  meters are used.

  比如说, 要计算清远和广州之间的距离, 我们可以执行以下代码:

  >>> r.geodist("Guangdong", "Qingyuan", "Guangzhou")

  52094.4338

  因为 GEODIST 命令默认使用米作为单位, 所以它返回了 52094.4338 米作为结果, 为了让这个结果更为直观一些, 我们可以将 GEODIST 命令的单位从米改为千米(公里):

  >>> r.geodist("Guangdong", "Qingyuan", "Guangzhou", unit="km")

  52.0944

  现在, 我们可以更直观地看到清远和广州之间相距 52.0944 公里了。

  范围查找

  Redis 的 GEORADIUS 命令 和 GEORADIUSBYMEMBER 命令 可以让买二手手机号码用户基于指定的地理位置或者已有的地理位置进行范围查找, redis-py 也通过同名的 georadius() 方法和 georadiusbymember() 方法来执行这两个命令。

  以下是 georadius() 方法的文档:

  georadius(self, name, longitude, latitude, radius, unit=None, withdist=False, withcoord=False, withhash=False, count=None, sort=None, store=None, store_dist=None) method of redis.clientis instance

  Return the members of the of the specified key identified by the

  nameargument which are within the borders of the area specified

  with the latitude and longitude location and the maxium

  distnance from the center specified by the radius value.

  The units must be one o fthe following : m, km mi, ft. By default

  withdist indicates to return the distances of each place.

  withcoord indicates to return the latitude and longitude of

  each place.

  withhash indicates to return the geohash string of each place.

  count indicates to return the number of elements up to N.

  sort indicates to return the places in a sorted way, ASC for

  nearest to fairest and DESC for fairest to nearest.

  store indicates to save the places names in a sorted set named

  with a specific key, each element of the destination sorted set is

  populated with the score got from the original geo sorted set.

  store_dist indicates to save the places names in a sorted set

  named with a sepcific key, instead of store the sorted set

  destination score is set with the distance.

  而以下则是 georadiusbymember() 方法的文档:

  georadiusbymember(self, name, member, radius, unit=None, withdist=False, withcoord=False, withhash=False, count=None, sort=None, store=None, store_dist=None) method of redis.clientis instance

  This command is exactly like georadius with the sole difference

  that instead of taking, as the center of the area to query, a longitude

  and latitude value, it takes the name of a member already existing

  inside the geospatial index represented by the sorted set.

  作为例子, 以下代码展示了如何通过给定深圳的地理坐标(114.0538788,22.5551603)来查找位于它指定范围之内的其他城市, 这一查找操作是通过 georadius() 方法来完成的:

  >>> r.georadius("Guangdong", 114.0538788, 22.5551603, 100, unit="km", withdist=True)

  [] # 没有城市在深圳的半径 100 公里之内

  >>> r.georadius("Guangdong", 114.0538788, 22.5551603, 120, unit="km", withdist=True)

  [['Foshan', 109.4922], ['Guangzhou', 105.8065]] # 佛山和广州都在深圳的半径 120 公里之内

  >>> r.georadius("Guangdong", 114.0538788, 22.5551603, 150, unit="km", withdist=True)

  [['Foshan', 109.4922], ['Guangzhou', 105.8065], ['Qingyuan', 144.2205]] # 佛山、广州和清远都在深圳的半径 150 公里之内

  另一方面, 以下代码则展示了如何通过 georadiusbymember() 方法, 找出位于广州指定半径范围内的其他城市:

  >>> r.georadiusbymember("Guangdong", "Guangzhou", 30, unit="km", withdist=True)

  [['Guangzhou', 0.0], ['Foshan', 17.9819]] # 佛山在广州的半径 30 公里范围之内

  >>> r.georadiusbymember("Guangdong", "Guangzhou", 100, unit="km", withdist=True)

  [['Foshan', 17.9819], ['Guangzhou', 0.0], ['Qingyuan', 52.0944]] # 佛山和清远都在广州的半径 100 公里范围之内获取 geohash

  最后, 用户可以通过 geohash() 方法调用 GEOHASH 命令, 以此来获得指定地理位置的 geohash 值, 以下是该方法的文档:

  geohash(self, name, *values) method of redis.clientis instance

  Return the geo hash string for each item of values members of

  the specified key identified by the nameargument.

  作为例子, 以下代码展示了如何获取清远、广州和佛山的 geohash 值:

  >>> r.geohash("Guangdong", "Qingyuan", "Guangzhou", "Foshan")

  ['ws0w0phgp70', 'ws0e89curg0', 'ws06vu9s0j0']结语

  好的, 这次关于使用 redis-py 处理 GEO 数据的介绍就到此结束, 希望这篇文章能够帮助大家更好地了解 redis-py 对 GEO 数据的支持, 也希望这个新版本的 redis-py 能够尽早释出, 让大家能够尽快地在 redis-py 里面用上 GEO 命令。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
缓存 NoSQL 关系型数据库
13- Redis和Mysql如何保证数据⼀致?
该内容讨论了保证Redis和MySQL数据一致性的几种策略。首先提到的两种方法存在不一致风险:先更新MySQL再更新Redis,或先删Redis再更新MySQL。第三种方案是通过MQ异步同步以达到最终一致性,适用于一致性要求较高的场景。项目中根据不同业务需求选择不同方案,如对一致性要求不高的情况不做处理,时效性数据设置过期时间,高一致性需求则使用MQ确保同步,最严格的情况可能涉及分布式事务(如Seata的TCC模式)。
51 6
|
1月前
|
存储 NoSQL 算法
09- Redis分片集群中数据是怎么存储和读取的 ?
Redis分片集群使用哈希槽分区算法,包含16384个槽(0-16383)。数据存储时,通过CRC16算法对key计算并模16383,确定槽位,进而分配至对应节点。读取时,根据槽位找到相应节点直接操作。
66 12
|
1月前
|
NoSQL Redis
05- Redis的数据淘汰策略有哪些 ?
Redis 提供了 8 种数据淘汰策略:挥发性 LRU、LFU 和 TTL(针对有过期时间的数据),挥发性随机淘汰,以及全库的 LRU、LFU 随机淘汰,用于在内存不足时选择删除。另外,还有不淘汰策略(no-eviction),允许新写入操作报错而非删除数据。
307 1
|
1月前
|
存储 NoSQL Redis
04- Redis的数据过期策略有哪些 ?
Redis的数据过期策略包括**惰性删除**和**定期删除**。惰性删除在取出key时检查是否过期,节省CPU但可能延迟清理。定期删除则每隔一定时间删除一批过期key,通过限制操作频率减少CPU影响。默认每秒扫描10次,随机抽取20个键,若25%已过期则继续检查,最大执行时间25ms。Redis使用这两种策略的结合以平衡内存和CPU使用。
17 1
|
1月前
|
缓存 NoSQL 算法
17- 数据库有1000万数据 ,Redis只能缓存20w数据, 如何保证Redis中的数据都是热点数据 ?
保证Redis中的20w数据为热点数据,可以通过设置Redis的LFU(Least Frequently Used)淘汰策略。这样,当数据库有1000万数据而Redis仅能缓存20w时,LFU会自动移除使用频率最低的项,确保缓存中的数据是最常使用的。
63 8
|
2天前
|
存储 NoSQL 算法
深入浅出Redis(三):Redis数据的存储、删除以及淘汰
深入浅出Redis(三):Redis数据的存储、删除以及淘汰
|
6天前
|
存储 NoSQL 测试技术
Redis数据存储系统为什么快?
Redis的快速并非偶然,而是深思熟虑的设计理念的结果。通过将数据存储于内存、采用单线程模型、实现非阻塞I/O等独特的技术选择,Redis在高并发和低延迟方面展现了卓越的表现。
33 16
|
16天前
|
存储 缓存 NoSQL
Redis入门到通关之Redis缓存数据实战
Redis入门到通关之Redis缓存数据实战
22 0
|
16天前
|
存储 运维 监控
|
17天前
|
JSON NoSQL Java
SpringDataRedis 操作 Redis,并指定数据序列化器
SpringDataRedis 操作 Redis,并指定数据序列化器
17 1