dot Redis 8 已发布——它是开源的

了解更多

构建医疗服务提供者查找器

对于患者来说,在医疗保健领域中寻找信息可能令人困惑。术语和选项通常不熟悉,甚至很难弄清楚如何开始。零售网站上常见的“商店查找器”功能可以帮助您根据邮政编码或邮编找到您附近的医生或其他医疗服务提供者。 

然而不幸的是,这项功能并不总是那么容易创建。我们生活在一个球体上,如果想在任何方向上查找给定距离内的位置,就必须将圆形投影到球体上,并使用一个并非完全简单的坐标系。所有这些都意味着不那么简单的数学计算。值得庆幸的是,Redis 拥有广泛的地理空间能力来帮助您构建此类功能。 

在这个问题中,我们要回答的最基本问题相当简单:“我附近的医疗服务提供者有哪些?” 为此,您需要医疗服务提供者列表、提供者的经纬度位置以及提问患者的位置。提供者列表可能如下所示

这是一个用于演示的小列表,但在 Redis 中,这个列表可能非常庞大,仅受可用内存量的限制。

查找患者的位置可以通过多种方式完成:反向 IP、邮政编码匹配(称为 geocoder) 或甚至设备 GPS。每种方法都有其优缺点和特定的实现细节,这些超出了本文的范围。然而,无论采用哪种方法,它们最终都将解析为经纬度。我们现在暂时假设位置为 53.5469, -113.4977。

将数据载入 Redis 可以是一次性操作,也可以随着提供者列表的变化定期更新。GEOADD 命令会将位置添加到所谓的 geoset 中。Geosets 是 Sorted Sets 的一种变体,它将经纬度编码为 GeoHash,并存储在 Sorted Set 成员的分数中。让我们看看它是怎样的:

> GEOADD providers -113.4967 53.5574 royal-alex
(integer) 1
> GEOADD providers -113.5313 53.5177 cross-cancer-institute
(integer) 1
> GEOADD providers -113.4283 53.4608 grey-nuns-community-hospital
(integer) 1
> GEOADD providers -113.5247 53.5205 university-of-alberta-hospital
(integer) 1
> GEOADD providers -113.6119 53.5207 misericordia-community-hospital
(integer) 1

本例中需要注意的是参数。第一个参数是 key,这在 Redis 中很常见。第二个参数是经度,第三个是纬度,最后一个参数是 member。(非常重要的是,经度和纬度的顺序与您通常看到的顺序是相反的。)

现在我们的数据已经载入系统,每当用户想查找提供者时,我们只需要运行一个 Redis 命令即可找到他们附近的位置: 

> GEORADIUS providers -113.4977 53.5469 5 km

第一个参数是之前使用的 key,第二个和第三个参数分别是用户的经度和纬度。第四和第五个参数是距离和单位(km 表示公里,mi 表示英里,f 表示英尺,m 表示米)。输出将如下所示:

1) "royal-alex"
2) "university-of-alberta-hospital"
3) "cross-cancer-institute"

具有附加功能的地理空间

上面的示例可以让患者找到最近的医疗机构,但如果他们想去找提供特定服务的提供者怎么办?如果他们需要提供多种专业服务的机构怎么办?Redis 也可以提供帮助。

我们将使用 Search and Query 模块,而不是使用 GEO 系列命令。Search and Query 具有更丰富的数据查询能力,同时保留了 GEO 系列命令的地理空间能力。然而,这些更丰富的能力确实要求我们首先创建一个 schema。

> FT.CREATE ft_providers SCHEMA name TEXT services TAG location GEO

这将创建一个名为 ft_providers 的索引,包含三个字段:nameserviceslocationname 是一个文本字段,可以存储人类语言;services 是一个标签字段,用于存储表示所提供服务的标签;最后,location 存储位置的经度和纬度。

现在,让我们将位置添加到索引中。我们将使用 FT.ADD 命令,该命令需要索引名称,然后是用于唯一标识文档的文档 ID,以及文档分数。之后,SCHEMA 保留字将选项与文档字段(字段名、值顺序跟随其后)区分开来。让我们看看:

> FT.ADD ft_providers royal-alex 1.0 FIELDS name "Royal Alex Hospital" services "kidneyclinic,footclinic,gastroscopy,geriatrics,intensivecare,plasticsurgery,ultrasound" location "-113.4967 53.5574"
OK
> FT.ADD ft_providers cross-cancer-institute 1.0 FIELDS name "Cross Cancer Institute" services "ultrasound,fluoroscopy,mri,mammography,physicaltherapy,tumourtriage" location "-113.5313 53.5177"
OK
> FT.ADD ft_providers grey-nuns-community-hospital 1.0 FIELDS name "Grey Nuns Community Hospital" services "respiratorytherapy,orthopedics,nucelarmedicine,labouranddelivery,fluoroscopy,intensivecare" location "-113.4283 53.4608"
OK
> FT.ADD ft_providers university-of-alberta-hospital 1.0 FIELDS name "University of Alberta Hospital" services "colonoscopy,intensivecare,nucelarmedicine,respiratorytherapy,gastroscopy" location "-113.5247 53.5205"
OK
> FT.ADD ft_providers misericordia-community-hospital 1.0 FIELDS name "Misericordia Community Hospital" services "orthopedics,geriatrics,footclinic,ultrasound,labouranddelivery" location "-113.6119 53.5207"
OK

 
一旦数据进入 Search and Query,我们就可以开始搜索设施了。在 Search and Query 中,我们使用一个名为 FT.SEARCH 的命令。第一个参数是要搜索的索引,第二个参数是 query。在 Search and Query 中,您指定一个查询来确定返回给您的结果。查询可以非常简单,也可以非常复杂,但与某些其他数据库不同的是,Search and Query 的查询从不执行任何管理或破坏性操作。

假设您想查找上述示例位置附近的提供者,但只想查找提供超声波服务的提供者。在 Search and Query 中,查询将如下所示

> FT.SEARCH ft_providers "@location:[-113.4967 53.5574 5 km] @services:{ultrasound}"
1) (integer) 2
2) "cross-cancer-institute"
3) 1) "name"
   2) "Cross Cancer Institute"
   3) "location"
   4) "-113.5313 53.5177"
   5) "services"
   6) "ultrasound,fluoroscopy,mri,mammography,physicaltherapy,tumourtriage"
4) "royal-alex"
5) 1) "name"
   2) "Royal Alex Hospital"
   3) "location"
   4) "-113.4967 53.5574"
   5) "services"
   6) "kidneyclinic,footclinic,gastroscopy,geriatrics,intensivecare,plasticsurgery,ultrasound"

 
Search and Query 中,@ 符号表示“在特定字段中搜索”。查询的第一部分是针对名为 location 的地理空间字段的搜索子句。您会注意到方括号之间是与 GEORADIUS 命令中相同的参数:经度后跟纬度,然后是搜索半径和单位。第二个 @ 符号后跟字段名 services, 这意味着我们正在搜索每个文档的 services 字段。大括号内是该字段必须包含的标签名称。在本例中,我们查找包含 ultrasound 标签的文档。location 和 services 搜索子句之间有一个空格——在 Search and Query 中,这是一个隐式的 AND。 

构建 UI 时,您可以将各种用户输入组合到同一个查询中以优化结果。下面是这种工作方式的粗略示意图

从您的应用程序的角度来看,UI 元素是字符串的一种表示,当它们改变时,您将它们模板化到传递给 FT.SEARCH 的字符串中。在 SQL 查询等内容中进行字符串插值是危险的(参见 little Bobby Tables),因为 SQL 语言存在管理操作。相比之下,Search and Query 的查询只能查找文档而不能执行管理操作,因此只需要简单的输入验证和健全性检查。

提高搜索的复杂度,如果用户同时勾选 ultrasoundgeriatrics,您可以更改 services 子句,在两个标签之间插入管道符(|) 来包含两者,如下所示: 

> FT.SEARCH ft_providers "@location:[-113.4967 53.5574 5 km] @services:{ultrasound|geriatrics}"
1) (integer) 2
2) "royal-alex"
3) 1) "name"
   2) "Royal Alex Hospital"
   3) "location"
   4) "-113.4967 53.5574"
   5) "services"
   6) "kidneyclinic,footclinic,gastroscopy,geriatrics,intensivecare,plasticsurgery,ultrasound"
4) "cross-cancer-institute"
5) 1) "name"
   2) "Cross Cancer Institute"
   3) "location"
   4) "-113.5313 53.5177"
   5) "services"
   6) "ultrasound,fluoroscopy,mri,mammography,physicaltherapy,tumourtriage"

 
Search and Query 足够灵活,几乎可以处理您在此类应用程序中所需的任何其他功能。名称和名称前缀搜索、同音名称、街道名称等操作都只是此类查询的增量步骤。例如,您可以通过在 schema 中包含一个数字字段来添加酷炫的等待时间功能——因为 Search and Query 是一个实时搜索引擎,可以快速更新此值,因此尝试查找等待时间最短的提供者的患者将始终获得最新结果。

Redis 可以帮助您通过几行代码构建一个简单的医疗服务提供者查找器,而 Search and Query 几乎可以满足您可能需要的任何功能,以便患者找到满足其需求的提供者。由于 Redis 和 Search and Query 具有内置的地理空间能力,您无需进行任何数学计算。Search and Query 为您提供丰富的查询能力,可以安全地接受患者的输入,并且能够实时更新,这意味着您可以在不向患者提供过时信息的情况下进行更改。