amazon-dynamodb - 如何在 DynamoDB 中实现按项目的任意属性排序
问题描述
我有一个 DynamoDB 结构如下。
- 我有患者的患者信息存储在其文档中。
- 我的索赔信息存储在其文件中。
- 我的付款信息存储在其文件中。
- 每个索赔都属于患者。患者可以有一项或多项索赔。
- 每笔付款都属于患者。患者可以有一笔或多笔付款。
我只创建了一个 DynamoDB 表,因为所有的 aws dynamodb 文档都表明如果可能只使用一个表是最好的解决方案。所以我最终得到以下结果:
在这个表中,ID 是分区键,EntryType 是排序键。每项索赔和付款都持有其所有者。我的访问模式如下:
- 列出数据库中的所有患者,并按创建日期对患者进行分页。
- 列出数据库中的所有声明,并按创建日期对声明进行分页。
- 列出数据库中的所有付款,并按创建日期排序付款。
- 列出特定患者的索赔。
- 列出特定患者的付款。
我可以通过两个全局二级索引来实现这些。我可以使用 GSI 将 EntryType 作为分区键,将 CreationDate 作为排序键,以列出按创建日期排序的患者、索赔和付款。我还可以使用另一个 GSI 和 EntryType 分区键和 OwnerID 排序键列出患者的索赔和付款。
我的问题是这种方法只给我带来了创建日期的排序。我的患者和索赔有更多的属性(每个大约 25 个),我还需要根据他们的每个属性对它们进行排序。但是 Amazon DynamoDB 有一个限制,即每个表最多可以有 20 个 GSI。因此,我尝试动态创建 GSI(根据请求动态创建),但这也以非常低效的方式结束,因为它将项目复制到另一个分区以创建 GSI(据我所知)。那么,按照患者姓名、索赔描述以及他们拥有的任何其他字段对患者进行分类的最佳解决方案是什么?
解决方案
DynamoDB 中的排序仅在排序键上发生。在您的数据模型中,您的排序键是EntryType
,它不支持您概述的任何访问模式。
您可以在要排序的字段上创建二级索引(例如creationDate
)。但是,如果您想支持按许多属性进行排序,则该模式可能会受到限制。
恐怕您的问题没有简单的解决方案。虽然这在 SQL 中非常简单,但 DynamoDB 排序并不能那样工作。相反,我会提出一些可以帮助你摆脱困境的想法:
- 客户端排序- 使用 DDB 高效查询应用程序所需的数据,让客户端不必担心数据排序。例如,如果您的客户端是一个 Web 应用程序,您可以使用 javascript 动态地对字段进行排序,具体取决于用户想要排序的字段。
- 考虑为您的 ID使用KSUID - 我注意到您的大多数访问模式都涉及按
CreationDate
. KSUID 或 K-Sortable Globally Unique Id's 是可按生成时间排序的全局唯一 ID。当您的应用程序需要创建唯一 ID并按创建时间戳排序时,这是一个很好的选择。如果您将 KSUID 构建到排序键中,您的查询结果可以自动支持按创建日期排序。 - 重新组织您的数据- 如果您可以灵活地重新设计存储数据的方式,您可以使用更少的二级索引来适应多种访问模式(下面的示例)。
最后,我注意到您的表示例非常“扁平”,并且似乎没有以支持您的任何访问模式(不添加索引)的方式对关系进行建模。也许这只是一个示例数据集,以突出您关于排序的问题,但我想解决一种不同的方法来对您的数据建模,以防您不熟悉这些模式。
例如,考虑要求您获取患者的索赔和付款的访问模式,按创建日期排序。这是可以建模的一种方式:
此设计处理四种访问模式:
- 获取患者索赔,按创建日期排序。
- 获取患者付款,按创建日期排序。
- 获取患者信息(姓名等)
- 获取患者索赔、付款和信息(在单个查询中)。
查询看起来像这样(在伪代码中):
- 查询 PK = "PATIENT#UUID1" 和 SK < "PATIENT#UUID1"
- 查询 PK = "PATIENT#UUID1" 和 SK > "PATIENT#UUID1"
- 查询 PK = "PATIENT#UUID1" 和 SK = "PATIENT#UUID1"
- 查询哪里 PK = "PATIENT#UUID1"
这些查询利用了按字典顺序排序的排序键。当您要求 DDB 获取排序键小于“PATIENT#UUID1”的PATIENT#UUID1 分区时,它将仅CLAIM
返回项目。这是因为按字母顺序排序时CLAIMS
出现在前面。PATIENT
同样的模式是我如何访问PAYMENT
给定患者的项目。我在这个场景中使用了 KSUID,它为您提供了按创建日期对CLAIMS
和项目进行排序的附加功能!PAYMENT
虽然这种模式可能无法解决您所有的排序问题,但我希望它能够为您提供一些想法,让您了解如何对数据进行建模以支持各种访问模式,并将排序功能作为副作用。
推荐阅读
- c - 稳健准确地计算两个浮点数的商的自然对数
- json - 对网站用户隐藏 JSON 文件并在 Android 应用程序中调用它
- python - Flask & Boto3 `ValueError: Required parameter name not set` on Accessing Resource
- php - AZ、az、0-9、_、- 和一个空格的 PHP preg_match
- xctest - 从 Xcode 运行测试时,将调用 XCTestObservation 下的函数 testSuiteWillStart
- rust - 无法返回可变的自我借用
- postgresql - Postgres 在 FOR 循环中访问行值
- regex - RegEx - 仅匹配开头有美元符号的字符串
- amazon-web-services - AWS CodeDeploy 无法部署 lambda 函数
- python - 如何将http附加到每个url的文本文件