DynamoDB 邻接列表是否应该使用离散的分区键来为每种类型的关系建模?
Should DynamoDB adjacency lists use discrete partition keys to model each type of relationship?
上下文
我正在构建一个论坛并研究使用 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
此外,对于下面的每个 table,将有一个等效的全局二级索引,其中交换了分区键和排序键。
示例数据
这是我想在 DynamoDB 中建模的内容:
- Harry 喜欢评论 A
- Harry 喜欢评论 B
- Harry 关注评论 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"
这种方法的缺点是查询结果中存在冗余信息,因为它们会 return 额外的您可能不关心的项目。例如,如果你想查询喜欢给定评论的所有用户,你还必须处理关注的所有用户] 给出的评论。同样,如果要查询一个用户喜欢的所有评论,则需要处理一个用户关注.[=17]的所有评论=]
选项 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
完全跳过邻接表并使用单独的 tables,可能一个用于 Users
,一个用于 Likes
,一个用于 Follows
。
选项 4
传统关系数据库。虽然我不打算走这条路,因为这是一个个人项目,我想探索 DynamoDB,但如果 是 思考事情的正确方式,我很想听听为什么。
结论
感谢您阅读到这里!如果我能做些什么来简化问题或澄清任何事情,请告诉我:)
我看过AWS best practices and this many-to-many SO post,但似乎都没有解决多对多(有很多)关系,因此非常感谢任何资源或指导。
您的选项 1 不可行,因为它没有唯一的主键。在您的示例数据中,您可以看到 (Comment-A, User-Harry)
.
有两个条目
解决方案 1
实现您正在寻找的方法是为您的 table 和 GSI 使用稍微不同的属性。如果哈利喜欢评论A,那么你的属性应该是:
hash_key: User-Harry
gsi_hash_key: Comment-A
sort_key_for_both: Likes-User-Harry-Comment-A
现在您在 table 和 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 事务,以这种方式保存 "like" 实际上可以是完全 ACID 操作。
上下文
我正在构建一个论坛并研究使用 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
此外,对于下面的每个 table,将有一个等效的全局二级索引,其中交换了分区键和排序键。
示例数据
这是我想在 DynamoDB 中建模的内容:
- Harry 喜欢评论 A
- Harry 喜欢评论 B
- Harry 关注评论 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"
这种方法的缺点是查询结果中存在冗余信息,因为它们会 return 额外的您可能不关心的项目。例如,如果你想查询喜欢给定评论的所有用户,你还必须处理关注的所有用户] 给出的评论。同样,如果要查询一个用户喜欢的所有评论,则需要处理一个用户关注.[=17]的所有评论=]
选项 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
完全跳过邻接表并使用单独的 tables,可能一个用于 Users
,一个用于 Likes
,一个用于 Follows
。
选项 4
传统关系数据库。虽然我不打算走这条路,因为这是一个个人项目,我想探索 DynamoDB,但如果 是 思考事情的正确方式,我很想听听为什么。
结论
感谢您阅读到这里!如果我能做些什么来简化问题或澄清任何事情,请告诉我:)
我看过AWS best practices and this many-to-many SO post,但似乎都没有解决多对多(有很多)关系,因此非常感谢任何资源或指导。
您的选项 1 不可行,因为它没有唯一的主键。在您的示例数据中,您可以看到 (Comment-A, User-Harry)
.
解决方案 1
实现您正在寻找的方法是为您的 table 和 GSI 使用稍微不同的属性。如果哈利喜欢评论A,那么你的属性应该是:
hash_key: User-Harry
gsi_hash_key: Comment-A
sort_key_for_both: Likes-User-Harry-Comment-A
现在您在 table 和 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 事务,以这种方式保存 "like" 实际上可以是完全 ACID 操作。