首页 > 解决方案 > 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 中建模的内容:

  1. 哈利喜欢评论A
  2. 哈利喜欢评论B
  3. 哈利关注评论 A
  4. 罗恩喜欢评论B
  5. 赫敏喜欢评论 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

这使得独立查询变得高效:

  1. 评论喜欢
  2. 评论如下
  3. 用户喜欢
  4. 用户关注

缺点是同一个顶级实体现在有多个键,随着更多关系的添加,这可能会使事情变得复杂。

选项 3

完全跳过邻接列表并使用单独的表,可能一张 for Users,一张 for Likes,一张 for Follows

选项 4

传统的关系数据库。虽然我不打算走这条路,因为这是一个个人项目并且我想探索 DynamoDB,但如果这思考问题的正确方式,我很想听听为什么。

结论

感谢您阅读到这里!如果我可以做些什么来简化问题或澄清任何事情,请告诉我:)

我查看了AWS 最佳实践和这篇多对多 SO 帖子,但似乎都没有解决多对多(多)关系,因此非常感谢任何资源或指导。

标签: amazon-dynamodbforumadjacency-list

解决方案


您的选项 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-HarryComment A

如果您想对未来关系的更复杂信息进行建模(包括描述关系之间的关系的能力,例如Likes-User-Ron-User-Harry Causes Follows-User-Ron-User-Harry),这将为您提供灵活性。

但是,这种策略需要在数据库中存储更多的项目,这意味着保存“喜欢”(以便可以查询)不是原子操作。(但您可以通过仅编写关系实体来解决此问题,然后使用 DynamoDBStreams + Lambda 为我在此解决方案开头提到的两个条目编写条目。)

更新:使用 DynamoDB 事务,以这种方式保存“喜欢”实际上可以是一个完全的 ACID 操作。


推荐阅读