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

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容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
目录
相关文章
|
21天前
|
监控 NoSQL Java
场景题:百万数据插入Redis有哪些实现方案?
场景题:百万数据插入Redis有哪些实现方案?
35 1
场景题:百万数据插入Redis有哪些实现方案?
|
1天前
|
NoSQL Redis
Redis的数据淘汰策略有哪些 ?
Redis 提供了 8 种数据淘汰策略,分为淘汰易失数据和淘汰全库数据两大类。易失数据淘汰策略包括:volatile-lru、volatile-lfu、volatile-ttl 和 volatile-random;全库数据淘汰策略包括:allkeys-lru、allkeys-lfu 和 allkeys-random。此外,还有 no-eviction 策略,禁止驱逐数据,当内存不足时新写入操作会报错。
26 16
|
1天前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
25 14
|
1天前
|
存储 NoSQL 算法
Redis分片集群中数据是怎么存储和读取的 ?
Redis集群采用哈希槽分区算法,共有16384个哈希槽,每个槽分配到不同的Redis节点上。数据操作时,通过CRC16算法对key计算并取模,确定其所属的槽和对应的节点,从而实现高效的数据存取。
23 13
|
1天前
|
存储 NoSQL Redis
Redis的数据过期策略有哪些 ?
Redis 采用两种过期键删除策略:惰性删除和定期删除。惰性删除在读取键时检查是否过期并删除,对 CPU 友好但可能积压大量过期键。定期删除则定时抽样检查并删除过期键,对内存更友好。默认每秒扫描 10 次,每次检查 20 个键,若超过 25% 过期则继续检查,单次最大执行时间 25ms。两者结合使用以平衡性能和资源占用。
21 11
|
1天前
|
监控 NoSQL 测试技术
【赵渝强老师】Redis的AOF数据持久化
Redis 是内存数据库,提供数据持久化功能,支持 RDB 和 AOF 两种方式。AOF 以日志形式记录每个写操作,支持定期重写以压缩文件。默认情况下,AOF 功能关闭,需在 `redis.conf` 中启用。通过 `info` 命令可监控 AOF 状态。AOF 重写功能可有效控制文件大小,避免性能下降。
|
1天前
|
存储 监控 NoSQL
【赵渝强老师】Redis的RDB数据持久化
Redis 是内存数据库,提供数据持久化功能以防止服务器进程退出导致数据丢失。Redis 支持 RDB 和 AOF 两种持久化方式,其中 RDB 是默认的持久化方式。RDB 通过在指定时间间隔内将内存中的数据快照写入磁盘,确保数据的安全性和恢复能力。RDB 持久化机制包括创建子进程、将数据写入临时文件并替换旧文件等步骤。优点包括适合大规模数据恢复和低数据完整性要求的场景,但也有数据完整性和一致性较低及备份时占用内存的缺点。
|
1月前
|
消息中间件 缓存 NoSQL
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
50 2
|
21天前
|
存储 数据采集 监控
将百万数据插入到 Redis,有哪些实现方案
【10月更文挑战第15天】将百万数据插入到 Redis 是一个具有挑战性的任务,但通过合理选择实现方案和进行性能优化,可以高效地完成任务。
68 0
|
1月前
|
存储 NoSQL Redis
redis保存数据的结构-redisobject结构体
`redisObject`结构体是Redis内部数据组织的核心,它通过集成类型标识、引用计数和编码方式等关键信息,实现了数据的高效管理和访问。这种设计允许Redis根据数据的实际需求动态调整存储结构,既保证了内存使用的高效性,也确保了数据操作的灵活性和速度。通过对 `redisObject`的深入了解,可以更好地掌握Redis如何在内存中高效存储和操作数据,进而优化数据库的性能和资源利用。
19 0
下一篇
无影云桌面