python使用redis
我经常出差。 我不是一个小汽车人,所以当我有空闲时间时,我更喜欢在城市周围散步或骑自行车。 我去过商务旅行的许多城市都有单车共享系统,可让您租几个小时的自行车。 这些系统中的大多数系统都有一个可帮助用户定位和租赁自行车的应用程序,但是对于像我这样的用户,如果有一个地方可以获取城市中所有可供租赁的自行车的信息,将对您有所帮助。
Python编程语言,以及开源Redis内存数据结构服务器来索引和查询地理空间数据。最终的Bikeshare应用程序合并了来自许多不同共享系统的数据,包括纽约市的Citi Bike bikeshare。 它利用了Citi Bike系统提供的General Bikeshare Feed,并使用其数据演示了可以使用Redis构建的一些功能来为地理空间数据建立索引。 Citi Bike数据是根据Citi Bike数据许可协议提供的 。
通用Bikeshare Feed规范
通用Bikeshare Feed规范(GBFS)是由北美Bikeshare协会开发的开放数据规范 ,旨在使地图和运输应用程序更轻松地将Bikeshare系统添加到其平台中。 目前,世界上60多个不同的共享系统正在使用该规范。
提要由几个简单的JSON数据文件组成,这些文件包含有关系统状态的信息。 该提要以引用该子提要数据的URL的顶级JSON文件开头:
{
"data"
:
{
"en"
:
{
"feeds"
:
[
{
"name"
:
"system_information"
,
"url"
:
"https://gbfs.citibikenyc.com/gbfs/en/system_information.json"
}
,
{
"name"
:
"station_information"
,
"url"
:
"https://gbfs.citibikenyc.com/gbfs/en/station_information.json"
}
,
. . .
]
}
}
,
"last_updated"
:
1506370010
,
"ttl"
:
10
}
第一步是使用来自system_information
和station_information
提要的数据将有关共享单车站点的信息加载到Redis中。
system_information
提要提供系统ID,这是一个短代码,可用于为Redis密钥创建名称空间。 GBFS规范未指定系统ID的格式,但会确保它是全局唯一的。 许多bikeshare提要使用短名称(例如Coast_bike_share,boise_greenbike或topeka_metro_bikes)作为系统ID。 其他人则使用熟悉的地理缩写,例如NYC或BA,而一个人则使用通用唯一标识符(UUID)。 共享单车应用程序使用标识符作为前缀来构造给定系统的唯一键。
station_information
feed提供有关组成系统的共享站的静态信息。 站由具有多个字段的JSON对象表示。 车站对象中有几个必填字段,提供了物理自行车车站的ID,名称和位置。 还有一些可选字段可提供有用的信息,例如最近的十字路口或可接受的付款方式。 这是共享单车应用程序这一部分信息的主要来源。
建立资料库
我已经编写了一个示例应用程序load_station_data.py ,该应用程序模仿了从外部源加载数据的后端过程中将发生的情况。
寻找单车共享站
从GitHub上 GBFS 存储库中的systems.csv文件开始加载bikeshare数据。
存储库的systems.csv文件为具有可用GBFS提要的已注册Bikeshare系统提供发现URL。 发现URL是处理共享单车信息的起点。
load_station_data
应用程序获取在系统文件中找到的每个发现URL,并使用它查找两个子供稿的URL:系统信息和站点信息。 系统信息提要提供了一条关键信息:系统的唯一ID。 ( 注意:systems.csv文件中也提供了系统ID,但是该文件中的某些标识符与提要中的标识符不匹配,因此我总是从提要中获取标识符。)有关系统的详细信息,例如可以在应用程序的未来版本中添加bikeshare URL,电话号码和电子邮件,因此,使用键${system_id}:system_info
将数据存储在Redis哈希中。
加载站数据
工作站信息提供有关系统中每个工作站的数据,包括系统的位置。 load_station_data
应用程序遍历站供稿中的每个站,并使用格式${system_id}:station:${station_id}
的键将有关每个站的数据存储到Redis哈希中。 使用GEOADD
命令将每个站点的位置添加到共享单车的地理空间索引中。
更新数据
在后续运行中,我不希望代码从Redis中删除所有提要数据并将其重新加载到空的Redis数据库中,因此我仔细考虑了如何处理数据的就地更新。
该代码首先从数据集加载有关正在处理的系统的所有自行车共享站点的信息。 当为某个工作站加载信息时,该工作站(通过键)将从内存中的工作站集中删除。 加载所有站点数据后,我们将得到一个包含该系统必须删除的所有站点数据的集合。
应用程序在这组站点上进行迭代并创建事务以删除站点信息,从地理空间索引中删除站点密钥,以及从系统的站点列表中删除站点。
代码说明
示例代码中有一些有趣的事情要注意。 首先,使用GEOADD
命令将项目添加到地理空间索引,但使用GEOADD
命令将其ZREM
。 由于地理空间类型的基础实现使用排序集,因此将使用ZREM
删除项目。 请注意:为简单起见,示例代码演示了如何使用单个Redis节点。 事务块将需要重组以在集群环境中运行。
如果您使用的是Redis 4.0(或更高版本),则代码中还有一些DELETE
和HMSET
命令的替代方法。 Redis 4.0提供了UNLINK
命令作为DELETE
命令的异步替代。 UNLINK
将从密钥空间中删除密钥,但是它将在单独的线程中回收内存。 该HMSET
命令中的Redis 4.0弃用和HSET
现在命令是可变参数 (即,它接受的参数不定数)。
通知客户
在流程结束时,将根据我们的数据向客户发送通知。 使用Redis发布/ geobike:station_changed
机制,该通知通过带有系统ID的geobike:station_changed
通道发出。
资料模型
在Redis中构造数据时,要考虑的最重要的事情是如何查询信息。 bikeshare应用程序需要支持的两个主要查询是:
- 查找我们附近的车站
- 显示有关电台的信息
Redis提供了两种对存储我们的数据有用的主要数据类型:哈希和排序集。 哈希类型可以很好地映射到代表站点的JSON对象; 由于Redis哈希不强制执行架构,因此可以将其用于存储可变桩号信息。
当然,在地理上寻找站点需要地理空间索引来搜索相对于某些坐标的站点。 Redis提供了一些命令来使用已排序的集合数据结构来构建地理空间索引。
我们使用${system_id}:station:${station_id}
格式来构造包含有关站的信息的哈希的键,并使用${system_id}:stations:location
格式来构建用于查找站的地理索引。
获取用户的位置
构建应用程序的下一步是确定用户的当前位置。 大多数应用程序通过操作系统提供的内置服务来完成此任务。 操作系统可以为应用程序提供基于设备内置的GPS硬件的位置,或基于设备可用的WiFi网络的位置。
寻找站
找到用户的位置后,下一步是找到附近的自行车共享站点。 Redis的地理空间功能可以在距用户当前坐标给定距离内的站点上返回信息。 这是使用Redis命令行界面的示例。
![Apple NYC商店位置地图 Map of Apple NYC store location](https://i-blog.csdnimg.cn/blog_migrate/e402ec7199be2d0e46d6045028e035a9.png)
想象一下,我在纽约第五大道的Apple Store商店,我想前往市区的西37号Mood,赶上我的好友Swatch 。 我可以乘出租车或地铁,但我更喜欢骑自行车。 请问附近有没有共享站可供我骑自行车旅行?
苹果商店位于40.76384,-73.97297。 根据地图,两个自行车共享站-大军广场和中央公园南以及东58街和麦迪逊-落在商店500英尺半径内(在上面的地图中为蓝色)。
我可以使用Redis的GEORADIUS
命令来查询NYC系统索引以获取500英尺半径范围内的站点:
127.0.0.1
:
6379
> GEORADIUS NYC
: stations
: location
-
73.97297
40.76384
500 ft
1
)
"NYC:station:3457"
2
)
"NYC:station:281"
Redis使用我们的地理空间索引中的元素作为有关特定站点的元数据的键,返回在该半径内找到的两个共享自行车位置。 下一步是查找两个工作站的名称:
127.0.0.1
:
6379
> hget NYC
: station
:
281 name
"Grand Army Plaza & Central Park S"
127.0.0.1
:
6379
> hget NYC
: station
:
3457 name
"E 58 St & Madison Ave"
这些键对应于上面地图上标识的站点。 如果需要,可以向GEORADIUS
命令添加更多标志,以获取元素列表,它们的坐标以及它们与当前点的距离:
127.0.0.1
:
6379
> GEORADIUS NYC
: stations
: location
-
73.97297
40.76384
500 ft WITHDIST WITHCOORD ASC
1
)
1
)
"NYC:station:281"
2
)
"289.1995"
3
)
1
)
"-73.97371262311935425"
2
)
"40.76439830559216659"
2
)
1
)
"NYC:station:3457"
2
)
"383.1782"
3
)
1
)
"-73.97209256887435913"
2
)
"40.76302702144496237"
查找与这些键关联的名称会生成一个可供选择的电台的有序列表。 Redis不提供方向或路线选择功能,因此我使用设备操作系统的路线选择功能来绘制从当前位置到所选自行车站的路线。
GEORADIUS
功能可以在您喜欢的开发框架中的API内轻松实现,以向应用程序添加位置功能。
其他查询命令
除了GEORADIUS
命令之外,Redis还提供了三个其他命令来从索引中查询数据: GEOPOS
, GEODIST
和GEORADIUSBYMEMBER
。
GEOPOS
命令可以提供来自geohash的给定元素的坐标。 例如,如果我知道在West 38th和8th有一个共享单车的站点,其ID为523,则该站点的元素名称为NYC:station:523。 使用Redis,我可以找到站点的经度和纬度:
127.0.0.1
:
6379
> geopos NYC
: stations
: location NYC
: station
:
523
1
)
1
)
"-73.99138301610946655"
2
)
"40.75466497634030105"
GEODIST
命令提供索引的两个元素之间的距离。 如果我想找到大军广场和中央公园南站之间的距离与东58街和麦迪逊站之间的距离,我会发出以下命令:
127.0.0.1
:
6379
> GEODIST NYC
: stations
: location NYC
: station
:
281 NYC
: station
:
3457 ft
"671.4900"
最后, GEORADIUSBYMEMBER
命令类似于GEORADIUS
命令,但是该命令采用索引的另一个成员的名称,而不是获取一组坐标,并返回以该成员为中心的给定半径内的所有成员。 要查找位于大军广场和中央公园南1000英尺范围内的所有车站,请输入以下内容:
127.0.0.1
:
6379
> GEORADIUSBYMEMBER NYC
: stations
: location NYC
: station
:
281
1000 ft WITHDIST
1
)
1
)
"NYC:station:281"
2
)
"0.0000"
2
)
1
)
"NYC:station:3132"
2
)
"793.4223"
3
)
1
)
"NYC:station:2006"
2
)
"911.9752"
4
)
1
)
"NYC:station:3136"
2
)
"940.3399"
5
)
1
)
"NYC:station:3457"
2
)
"671.4900"
尽管此示例着重于使用Python和Redis解析数据并建立共享单车系统位置的索引,但可以轻松地将其通用化以查找餐馆,公共交通或开发人员希望帮助用户查找的任何其他类型的地方。
本文基于我今年在Raleigh的Open Source 101上的演讲 。
翻译自: https://opensource.com/article/18/2/building-bikesharing-application-open-source-tools
python使用redis