DynamoDB邻接表是否应使用离散分区键来模拟每种类型的关系?

10

背景

我正在构建一个论坛,并研究使用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. Harry 喜欢评论 A
  2. Harry 喜欢评论 B
  3. Harry 关注评论 A
  4. Ron 喜欢评论 B
  5. Hermione 喜欢评论 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"
这种方法的缺点是查询结果中存在冗余信息,因为它们会返回一些多余的条目,而这些条目可能并不是你关心的。例如,如果你想查询所有喜欢给定评论的用户,你也必须处理所有关注该评论的用户。同样,如果你想查询一个用户喜欢的所有评论,你需要处理该用户关注的所有评论。

选项二

修改键以表示关系:

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

完全跳过邻接列表,并使用单独的表,也许一张表用于用户,另一张表用于点赞,还有一张表用于关注。

选项4

传统的关系型数据库。虽然我不打算走这条路,因为这是一个个人项目,我想探索DynamoDB,但如果这是正确的思考方式,我很想知道原因。

结论

感谢阅读到这里!如果有任何可以简化问题或澄清任何事情的方法,请告诉我:)

我查看了AWS最佳实践和这篇many-to-many SO post,似乎都没有涉及到多对多(具有多个)关系,因此非常感谢任何资源或指导。

1个回答

8

你的 Option 1 不可行,因为它没有唯一的主键。在你的样本数据中,可以看到你有两个记录属于 (Comment-A, User-Harry)

Solution 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操作。


太好了!非常感谢您详细的回复。我真的很喜欢您的“Causes”想法所带来的可能性! - user3268232

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接