amazon-dynamodb - DynamoDB 邻接列表是否应该使用离散的分区键来为每种类型的关系建模?
问题描述
语境
我正在建立一个论坛并研究使用 DynamoDB 和邻接列表对数据进行建模。一些顶级实体(如用户)可能与其他顶级实体(如评论)具有多种类型的关系。
要求
例如,假设我们希望能够执行以下操作:
- 用户可以点赞评论
- 用户可以关注评论
- 评论可以显示喜欢它的用户
- 评论可以显示关注它的用户
- 用户个人资料可以显示他们喜欢的评论
- 用户个人资料可以显示他们关注的评论
因此,我们本质上是多对多(用户 <=> 评论)对多(喜欢或关注)。
注意:这个例子是故意精简的,在实践中会有更多的关系来建模,所以我试图在这里考虑一些可扩展的东西。
基线
以下顶级数据可能在任何邻接表表示中都很常见:
First_id(Partition key) Second_id(Sort Key) Data
------------- ---------- ------
User-Harry User-Harry User data
User-Ron User-Ron User data
User-Hermione User-Hermione User data
Comment-A Comment-A Comment data
Comment-B Comment-B Comment data
Comment-C Comment-C Comment data
此外,对于下面的每个表,将有一个等效的全局二级索引,其中交换了分区键和排序键。
示例数据
这就是我想在 DynamoDB 中建模的内容:
- 哈利喜欢评论A
- 哈利喜欢评论B
- 哈利关注评论 A
- 罗恩喜欢评论B
- 赫敏喜欢评论 C
选项1
使用第三个属性来定义关系类型:
First_id(Partition key) Second_id(Sort Key) Data
------------- ---------- ------
Comment-A User-Harry "LIKES"
Comment-B User-Harry "LIKES"
Comment-A User-Harry "FOLLOWS"
Comment-B User-Ron "LIKES"
Comment-C User-Hermione "FOLLOWS"
这种方法的缺点是查询结果中存在冗余信息,因为它们会返回您可能不关心的额外项目。例如,如果您想查询所有喜欢给定评论的用户,您还必须处理所有关注该给定评论的用户。同样,如果要查询用户喜欢的所有评论,则需要处理用户关注的所有评论。
选项 2
修改表示关系的键:
First_id(Partition key) Second_id(Sort Key)
------------- ----------
LikeComment-A LikeUser-Harry
LikeComment-B LikeUser-Harry
FollowComment-A FollowUser-Harry
LikeComment-B LikeUser-Ron
FollowComment-C FollowUser-Hermione
这使得独立查询变得高效:
- 评论喜欢
- 评论如下
- 用户喜欢
- 用户关注
缺点是同一个顶级实体现在有多个键,随着更多关系的添加,这可能会使事情变得复杂。
选项 3
完全跳过邻接列表并使用单独的表,可能一张 for Users
,一张 for Likes
,一张 for Follows
。
选项 4
传统的关系数据库。虽然我不打算走这条路,因为这是一个个人项目并且我想探索 DynamoDB,但如果这是思考问题的正确方式,我很想听听为什么。
结论
感谢您阅读到这里!如果我可以做些什么来简化问题或澄清任何事情,请告诉我:)
解决方案
您的选项 1 是不可能的,因为它没有唯一的主键。在您的示例数据中,您可以看到您有两个条目(Comment-A, User-Harry)
。
解决方案 1
实现您正在寻找的方法是为您的表和 GSI 使用稍微不同的属性。如果 Harry 喜欢 Comment A,那么你的属性应该是:
hash_key: User-Harry
gsi_hash_key: Comment-A
sort_key_for_both: Likes-User-Harry-Comment-A
现在,对于表和 GSI 中的顶级实体,您只有一个分区键值,您可以使用begins_with
运算符查询特定的关系类型。
解决方案 2
您可以使关系成为顶级实体。例如,数据库中有两个条目,因为它与和Likes-User-Harry-Comment-A
都“相邻” 。User-Harry
Comment A
如果您想对未来关系的更复杂信息进行建模(包括描述关系之间的关系的能力,例如Likes-User-Ron-User-Harry
Causes
Follows-User-Ron-User-Harry
),这将为您提供灵活性。
但是,这种策略需要在数据库中存储更多的项目,这意味着保存“喜欢”(以便可以查询)不是原子操作。(但您可以通过仅编写关系实体来解决此问题,然后使用 DynamoDBStreams + Lambda 为我在此解决方案开头提到的两个条目编写条目。)
更新:使用 DynamoDB 事务,以这种方式保存“喜欢”实际上可以是一个完全的 ACID 操作。
推荐阅读
- unit-testing - 测试在 jenkins 共享库中调用插件函数
- angularjs - 带有angularjs的松弛响应轮播
- sql-server - SQL Server 中的 DELETE 操作极慢
- c# - 正确地将 Serilog 注入 .net 核心类作为 Microsoft.Extentions.Logging.ILogger - 不是 ASP .Net Core
- javascript - 尽管选择的“用户名”已经存在,但用户在注册后被添加到 mongoDB 数据库
- c++ - 访问我以前可以访问的功能时出现分段错误
- performance - 多线程的 JMeter 仪表板报告
- c# - 我们如何使用“yield return”从 MediatR 请求处理程序返回 IAsyncEnumerable?
- sql - 是否可以使用链接表中的值更新本地表?
- api - Gridsome 返回 xml api - graphql 层