【问题标题】:Should DynamoDB adjacency lists use discrete partition keys to model each type of relationship?DynamoDB 邻接列表是否应该使用离散的分区键来为每种类型的关系建模?
【发布时间】:2019-04-20 20:30:22
【问题描述】:

上下文

我正在建立一个论坛并研究使用 DynamoDB 和邻接列表对数据进行建模。一些顶级实体(如用户)可能与其他顶级实体(如 cmets)有多种类型的关系。

要求

例如,假设我们希望能够执行以下操作:

  • 用户可以为 cmets 点赞
  • 用户可以关注cmets
  • 评论可以显示喜欢的用户
  • 评论可以显示关注它的用户
  • 用户个人资料可以显示他们喜欢的 cmets
  • 用户个人资料可以显示他们关注的 cmets

因此,我们本质上是多对多(用户 评论)对多(喜欢或关注)。

注意:这个例子是故意精简的,在实践中会有更多的关系来建模,所以我想在这里考虑一些可扩展的东西。

基线

以下顶级数据可能在任何邻接表表示中都很常见:

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. Harry 喜欢评论 B
  3. Harry 关注评论 A
  4. Ron 喜欢评论 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"

这种方法的缺点是查询结果中存在冗余信息,因为它们会返回您可能不关心的额外项目。例如,如果您想查询所有喜欢给定评论的用户,您还必须处理所有关注给定评论的用户。同样,如果要查询用户喜欢的所有cmets,则需要处理用户关注的所有cmets。

选项 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

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

选项 4

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

结论

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

我查看了AWS best practices 和这个many-to-many SO post 似乎都没有解决多对多(与多)关系,因此非常感谢任何资源或指导。

【问题讨论】:

    标签: amazon-dynamodb forum adjacency-list


    【解决方案1】:

    您的选项 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-HarryCausesFollows-User-Ron-User-Harry),这将为您提供灵活性。

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

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

    【讨论】:

    • 这太棒了!非常感谢您的详细回复。我真的很喜欢你的Causes 想法带来的可能性!
    猜你喜欢
    • 2015-07-06
    • 1970-01-01
    • 2011-06-17
    • 2019-09-26
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2010-09-18
    • 2017-09-23
    相关资源
    最近更新 更多