amazon-web-services - 通过 DynamoDB 建模帖子和主题
问题描述
这是我试图在 DynamoDB 中建模的关系:我的服务包含帖子和主题。一个帖子可能属于多个主题。一个主题可能有多个帖子。所有帖子都有一个兴趣值,该值将根据喜欢和发布时间的组合进行调整,兴趣衡量的是帖子在当前时刻的受欢迎程度。如果帖子太旧,它的兴趣值将是 0 并永远保持这种状态(存档)。
REST api 端点的工作方式如下:
- GET /posts/{id} 返回一个帖子对象,其中包含标题、文本、作者姓名和指向作者休息端点的链接(对于此示例无关紧要)和喜欢的数量(不包括兴趣值)
- GET /topics/{name} 应该返回一个对象,其中包含一个包含 N 个最新主题帖子的列表以及一个包含 N 个当前最有趣的帖子的列表
- POST /posts/ 创建一个可以指定多个主题的新帖子
- POST /topics/ 创建一个新主题
- POST /likes/ 为指定帖子创建点赞(实际上并不创建对象,只是将用户添加到给定帖子对象的点赞列表中,用户不可见)
现在的问题变成了,如何在 DynamoDB NoSql 中创建主题和帖子之间的关系?
我考虑在 DynamboDB 中添加一个帖子副本列表来标记条目,其中每个标签都有一个最新和最有趣的帖子列表。我可以做到这一点的一种方法是创建一个每 10 分钟运行一次并循环遍历每个主题对象的 cloudwatch 作业,找到最有趣和最新的条目,然后替换该主题的旧列表。另一项工作还必须定期更新每个未归档帖子的“兴趣”值(请记住,喜欢和时间都会对兴趣值产生影响)。
这样做的一个问题是,如果用户进行更改或删除帖子,标签列表中的许多帖子将过期 10 分钟。标签帖子列表上也不会正确跟踪喜欢。这也许可以通过事务来解决,尽管 dynamoDB 每个事务限制为 10 个对象。
另一个问题是,它需要 add-posts-to-tags 作业将所有未归档的帖子加载到内存中,以便按时间和兴趣手动对它们进行排序,按标签拆分它们,然后添加两者的前 N每 10 分钟设置一次标签列表。
我还有一个想法,通过将帖子的标签限制为1,我可以将标签添加为分区键,将发布时间作为排序键,并使用GSI添加兴趣作为第二个排序键。
不过,这确实有几个缺点:
- 非常流行的标签可能仅限于单个分区,因为所有帖子共享一个分区键
- 标签限制为 1
- 可能仍需要调整帖子兴趣值的 cloudwatch 作业
- 这将需要使用可能导致危险比赛条件的 GSI
但它的优点是除了 GSI 之外没有 post 对象的复制。它还将允许按日期对所有帖子进行基本上无限分页,而不是仅限于 N 个最新帖子。
那么这里有什么好的方法呢?它接缝我的两个解决方案都有可怕的交易破坏者。这只是 NoSQL 根本无法解决的问题之一吗?
解决方案
您正在尝试使用非关系数据库对关系数据进行建模,为此我将使用 2 种类型的数据库,我会将您示例中的帖子信息存储在发电机中:
GET /posts/{id}
POST /posts/
POST /likes/creates
对于主题相关信息,我将使用弹性搜索(Amazon Elasticsearch Service)
GET /topics/{name}
:搜索索引将存储完整的主题信息以及帖子 ID,以及您要搜索的相关字段(在您的情况下更新日期以获取最新帖子)
这将需要的是后台进程(在 dynamoDB 中,这可以通过流来完成),它对 dynamoDB 进行更改以获取新帖子,更新为喜欢计数等,并填充搜索索引。
注意:这也可以使用 graphDB 来解决,但出于扩展目的,最好将数据源(帖子)和数据关系(主题)分开。
推荐阅读
- terraform - 如何在 Terraform 中重用资源中的数据?
- coq - if-then-else 条件下的案例拆分
- asp.net-core-webapi - 发布时无法命中 AspNetCore 3.1 MVC API 端点
- groovy - 编写 DRY Spock 测试
- javascript - Heroku 在部署时进行故障排除
- mysql - 如何从 MySQL 中的同一张表中计算两个不同的值?
- javascript - 社交网络网站的数据库架构?mysql?
- java - 匿名类可以完全不可变吗?
- velocity - 在apache速度中重复字符串
- postgresql - 如何使用 Liquibase 的 Timescale 创建物化视图?