DynamoDB 邻接表主键

DynamoDB adjacency list primary key

我正在完成一个使用 DynamoDB 建模多对多关系的练习。我需要允许 post 和标签之间存在多对多关系。每个 post 可以有多个标签,每个标签可以有多个 post。

我在 id 上有一个主键,在 type 上有一个主排序键,然后在 iddata 上有另一个全局索引,我在上添加了另一个全局索引再次 idtype 但我认为这是多余的。

这是我目前的情况。

id(Partition key)      type(Sort Key)       target       data
-------------          ----------           ------       ------
1                      post                 1            cool post
tag                    tag                  tag          n/a
1                      tag                  tag          orange

---------------------------------------------
---- inserting another tag will overwrite ---
---------------------------------------------

1                      tag                  tag          green

我正在听取这个很棒的演讲的建议https://www.youtube.com/watch?v=jzeKPKpucS0 and these not so awesome docs https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html

我遇到的问题是,如果我尝试添加另一个带有 id“1”和 type"tag" 的标签,它将覆盖现有标签,因为它会相同的组合键。我在这里错过了什么?似乎建议是将主键和排序键设置为 idtype。我应该让我的类型更像 "tag#orange" 吗?在那种情况下,我可以在 target 上放置一个全局索引,并在类型上放置一个排序键。这样我就可以通过查询 target = "tag" 并键入以 "tag".

开头的特定标签来获取所有 posts

只是在寻找一些关于使用 Dynamo 处理这种邻接列表数据的建议,因为它看起来非常有趣。谢谢!

我认为您没有遗漏任何东西。这个想法是 ID 对于项目类型是唯一的。通常,您会为 ID 生成一个长 UUID,而不是使用序列号。另一种选择是使用您创建项目的日期时间,可能会添加一个随机数以避免在创建项目时发生冲突。

我之前提供的这个答案可能会有一点帮助DynamoDB M-M Adjacency List Design Pattern

不要删除排序键 - 这无助于使您的项目更加独特。

邻接表的基本准则

您需要对建模方式进行一些修改。在邻接列表中,您有两种类型的项目:

  1. 顶级(那些是你的Posts标签)
  2. 关联(表示哪些标签与每个Post 反之亦然)

要构建此邻接表,您必须遵循两个简单的准则(我认为您的示例中缺少这些准则):

  • 每个顶级项目(在您的例子中是 PostTag) 必须使用主键表示。此外,这些项目在排序键和主键中应具有相同的值
  • 对于关联,使用主键表示 source(或 parent),使用排序键表示 目标(或)。

根据我在你的例子中看到的情况,你设置了 PostsTags 作为项目 ID,同时您还应该使用它的 type;例如Post-1Tag-3。在代表关联的项目中,我也没有看到您存储目标 ID.

例子

假设您有:

  • 三个 Post:"hello world""foo bar""Whatever ..."
  • 还有三个标签:“酷”“很棒”“很棒”
  • Post "hello world" 有一个标签:"cool"
  • Post "foo bar" 有两个标签:"cool""great"
  • Post “随便...” 没有任何标签

您需要在 Dynamo 中以这种方式建模:

PRIMARY-KEY   | SORT-KEY    | SOURCE DATA  | TARGET DATA
--------------|-------------|--------------|-------------
Post-1        | Post-1      | hello world  |
Post-2        | Post-2      | foo bar      |
Post-3        | Post-3      | Whatever...  |
Tag-1         | Tag-1       | cool         |
Tag-2         | Tag-2       | awesome      |
Tag-3         | Tag-3       | great        |
Post-1        | Tag-1       | hello world  | cool
Post-2        | Tag-1       | foo bar      | cool
Post-2        | Tag-3       | foo bar      | great
Tag-1         | Post-1      | cool         | hello world
Tag-1         | Post-2      | cool         | foo bar
Tag-3         | Post-2      | great        | foo bar

如何查询这个邻接表

1) 你需要一个特定的项目,比如 Post-1:

查询primary-key == "Post-1" & sort-key == "Post-1"-returns:仅Post-1

2) 您需要与 Post-2:

关联的所有标签

primary-key == "Post-2" & sort-key BEGINS_WITH "Tag-" - returns 查询:Tag-1Tag-3 关联。

检查the documentation关于begin_with关键条件表达式

3) 你需要所有 Posts 关联,比如 Tag-1:

查询 primary_key == "Tag-1" & sort-key BEGINS_WITH "Post-" - returns: Post-1Post-2 协会。

Note that, if you change the contents of a given post, you need to change the value in all association items as well.

You can also don't store the post and tag content in association items, which saves storage space. But, in this case, you'd need two queries in the example queries 2 and 3 above: one to retrieve associations, another to retrieve each source item data. Since querying is more expensive than storing data, I prefer to duplicate storage. But it really depends if your application is read-intensive or write-intensive. If read-intensive, duplicating content in associations gives you benefit of reducing read queries. If write-intensive, not duplicating content saves write queries to update associations when the source item is updated.

希望对您有所帮助! ;)