简单地说,我们现在是Redis

了解更多

GeoBike:使用Redis构建位置感知应用程序

作为开发者的拥护者,我经常出差复述,!我不是一个喜欢开车的人,所以当我有一些空闲时间,我更喜欢步行或骑自行车在城市里转转。我去过的许多城市都有自行车共享系统,可以让你借几个小时的自行车。大多数这些系统都有一个租车应用程序,但它们只分享系统的细节。这让我思考——使用公共自行车共享信息来创建一个“应用程序”,向你展示全球信息,这将是一个有趣的方式来展示Redis的地理空间特征。有了GeoBike, Redis共享单车应用程序诞生了。

GeoBike整合了来自许多不同共享系统的数据,包括CITIBIKE BIKESHARE.在纽约市。我们将利用Citi自行车系统提供的一般Bikeshare Feed,并使用他们的数据来演示我们可以使用REDIS构建的一些功能来索引地理空间数据。CITIBIKE数据提供NYCBS数据使用政策

一般Bikeshare Feed规范

一般的Bikeshare Feed规范(GBFS)是一个开放数据规范开发的北美自行车共享协会为了使地图和运输应用程序更轻松地将自行车分享系统添加到其平台中。该规范目前在世界上有超过60种不同的共享系统使用。

提要由几个简单的JSON数据文件组成,其中包含关于系统状态的信息。提要以引用子提要数据url的顶级JSON文件开始:

我们将专注的第一件事是将有关自行车分享站的信息加载到Redis中。在我们申请的这一部分,我们将需要来自的数据system_information.station_information提要。

system_information.Feed将为我们提供系统ID,这是一个短代码,我们将用于为redis键创建名称空间。GBFS规范没有指定系统ID的格式,但保证它是全局唯一的。许多Bikeshare Feed都使用Succes_Bike_Share,Boise_Greenbike或Topeka_Metro_Bikes使用Shoct名称。其他人使用熟悉的地理缩写,例如NYC或BA,一个人使用UUID。我们的代码使用标识符作为前缀来构造给定系统的唯一密钥。

station_informationFeed提供关于组成系统的共享站的静态信息。站的代表是JSON有几个字段的对象。站对象中有几个强制性字段提供物理自行车站的ID,名称和位置。还有几个可选字段提供有用的信息,例如“交叉街”或“已接受的付款方式”。这是自行车共享应用程序的这一部分的主要信息来源。

建设我们的数据库

我写了一个示例应用程序,load_station_data.py,这模拟了从外部源加载数据时的后端进程。

寻找自行车股东

加载自行车份额数据systems.csv文件从GBFS在GitHub上的存储库

systems.csv文件提供已注册自行车共享系统的发现URL,并提供可用的GBFS提要。发现URL是处理共享单车信息的起点。

load_station_data应用程序获取在系统文件中找到的每个发现URL,并使用它查找两个子提要的URL:系统信息和站点信息。系统信息提要为我们提供了一个关键的信息片段:系统的唯一ID。注意,system .csv文件中也提供了系统ID,但是该文件中的一些标识符与提要中的标识符不匹配,因此我们总是从提要中获取标识符。该系统的详细信息,如租赁URL,电话号码和电子邮件可能在我们的应用程序的未来版本中有用,所以我们将使用密钥存储数据在Redis哈希中$ {system_id}: system_info

加载站数据

站点信息为我们提供了系统中每个站点的数据,包括系统的位置。的load_station_data应用程序在站馈送中的每个站迭代,并使用表单的键将有关该站的数据存储到Redis Hash中$ {system_id}:站:$ {station_id}.每个站的位置被添加到a中地理空间索引的自行车共享使用GEOADD命令。

更新数据

在随后的运行中,我们不希望我们的代码从Redis中删除所有的feed数据并重新加载到一个空的Redis数据库中,所以我们需要考虑如何处理数据的就地更新。

我们的代码通过加载集合,其中包含当前正在处理的系统的所有自行车共享站信息。当向站加载信息时,从内存的站集中移除站(按键)。一旦加载了所有站数据,我们都留下了一个包含必须删除此系统的所有站数据的集合。

我们的应用程序遍历这组站并创建一个事务来删除站信息,从地理空间索引中删除站键并从系统的站列表中删除该站。

有关守则的说明

在示例代码中有一些有趣的事情。首先,您会注意到我们使用的是使用物料添加到地理空间索引GEOADD命令,但使用ZREM.命令。地理空间类型的底层实现使用排序集,因此使用ZREM..注意:为了简单起见,示例代码演示了如何使用单个Redis节点;为了在集群环境中运行,需要重新构造事务块。

如果您使用的是redis 4.0(或更高版本),则会有一些替代方案删除HMSET代码中使用的命令。Redis 4.0提供解开的异步替代删除命令。UNLINK将从键空间中删除键,但在一个单独的线程中回收内存。的HMSET命令在Redis 4.0中已弃用,HSET命令现在是可变的。

通知客户

在这个过程的最后,我们向那些依赖我们数据的客户发送通知。使用Redis的Pub/Sub机制,我们发送一个通知geobike: station_changed使用系统ID的通道。

数据模型

在Redis中构造数据时,最重要的是要考虑如何查询信息。对于我们的共享单车应用程序,我们需要支持的两个主要查询是:

  • 寻找我们附近的车站
  • 显示有关站的信息

Redis提供了两个主要数据类型,可用于存储我们的数据,哈希和排序集。的哈希类型映射到表示站点的JSON对象,因为redis hashes无法强制执行架构,因此我们可以使用它们来存储我们的可变站信息。

当然,为了在地理上找到站点,我们需要构建一个地理空间索引来搜索相对于某些坐标的站点。复述,提供几个命令来建立一个地理空间索引排序集数据结构。

我们将使用这种格式构造键$ {system_id}:站:$ {station_id}用于包含使用该格式的站点和键的信息的散列$ {system_id}:站的位置用于用于查找站的地理空间索引。

映射结果

让我们通过生成加载到Redis的数据的地图来检查我们的数据负载的结果。我们可以通过构造一个地图来为数据创建一个地图KML(锁眼标记语言)文件并加载到谷歌地图.我已经提供了generate_station_kml.py.脚本生成站ID的电台位置的KML文件。Google Maps将KML文件限制为10层和5000个功能,因此KML Generator应用程序仅生成一个系统的文件。

该应用程序使用Redis-py scan_iter迭代站键(符合模式的键$ {system_id}:站:*),并使用Python Minidom包来构造输出XML。

我跑了这一点generate_station_kml.py.运行后,脚本对我的redis实例load_station_data.py并生成了以下纽约市城市自行车系统的地图。

地图示例:

如果我们寻找6号运河自行车站在我们的自定义地图上,我们在地图的基础层上看到Citibike站顶部的坐标40.72242,-74.00566和蓝色别针。当然这不是一个完整的QA循环,而是一种用来眼球以建立对代码的信心的好方法。

在下一个Geobike帖子中,我们将查看开发人员如何如何查询数据库中的数据以向应用程序添加有趣的功能。与此同时,您可以从Github上获取此帖子的关联代码。如果您对此帖子有任何疑问,请在推特上与我(@tague)连接。

Baidu