【问题标题】:How to design data storage for partitioned tagging system?如何设计分区标记系统的数据存储?
【发布时间】:2011-02-07 17:56:03
【问题描述】:

如何为庞大的标签系统(如digg或delicious)设计数据存储?

关于它已经有discussion,但它是关于集中式数据库的。由于数据应该会增长,因此我们迟早需要将数据划分为多个分片。那么问题就变成了:如何为分区标注系统设计数据存储?

标签系统基本上有3张表:

Item (item_id, item_content)

Tag (tag_id, tag_title)

TagMapping(map_id, tag_id, item_id)

如果表存储在一个数据库实例中,这对于查找给定标签的所有项目和查找给定项目的所有标签都很好。如果我们需要将数据分区到多个数据库实例中,那就没那么容易了。

对于表Item,我们可以用它的键item_id来划分它的内容。对于表 Tag,我们可以用它的键 tag_id 对它的内容进行分区。例如,我们要将表 Tag 分区为 K 个数据库。我们可以简单地选择数字 (tag_id % K) 数据库来存储给定的标签。

但是,如何对表进行分区TagMapping

TagMapping 表表示多对多关系。我只能想象有重复。也就是说,TagMappping的相同内容有两个副本。一个用 tag_id 分区,另一个用 item_id 分区。在为给定项目查找标签的场景中,我们使用带有 tag_id 的分区。如果要查找给定标签的项目,我们使用带有 item_id 的分区。

因此,存在数据冗余。并且,应用程序级别应该保持所有表的一致性。看起来很难。

有没有更好的方案来解决这个多对多的分区问题?

【问题讨论】:

    标签: database tags tagging partitioning


    【解决方案1】:

    您的查询很可能与用户主题相关。这意味着您应该在一个地方拥有与这些信息相关的所有信息。

    你说的是DB的分布,通常这主要是同步的问题。通常大约 90% 的工作可以在复制数据库上完成读取。问题是如何更新一个数据库并保持所有其他数据库的一致性,而不影响性能。这取决于您的场景详细信息。

    另一种可能性是按照您的要求对所有数据进行分区而不重叠。您可能会按用户 ID 或主题 ID 进行分区。如果您按主题 ID 进行分区,一个数据库可以引用所有主题,并且只告诉哪个专用数据库保存数据。然后,您可以查询正确的。由于您按 ID 进行分区,因此与该主题相关的所有信息都可能位于该专用数据库中。对于国际网站,您还可以按 languagecountry 进行分区。

    最后但并非最不重要的一点是,您最终可能会混合使用这两种数据:一些不重叠的数据和一些重叠(复制)的数据。首先找到通常的操作,然后找到如何在一个 DB 上以最少可能的查询进行操作。

    PS:别忘了缓存,它比分布式数据库更省钱。

    【讨论】:

      【解决方案2】:

      我怀疑是否有一种方法可以优化所有可能的使用场景。正如您所说,TagMapping 表支持两种主要方案:查找给定项目的标签,以及查找具有给定标签的项目。我认为对于每个可能感兴趣的场景,您将如何使用TagMapping 表存在一些差异。我只能根据典型的标记应用做出合理的假设,如果这太离谱了,请原谅我!

      查找给定项目的标签

      A1。您将一次显示给定项目的所有标签

      A2。您将确保项目的所有标签都是唯一的

      为给定标签查找项目

      B1。您将需要 一些 一次给定标签的项目(以填充搜索结果页面)

      B2。您可能允许用户指定多个标签,因此您需要找到 一些 匹配多个标签的项目

      B3。您将通过某种受欢迎程度对给定标签(或标签)的项目进行排序

      鉴于上述情况,我认为一个好的方法是按项目对TagMapping 进行分区。这样,给定项目的所有标签都在一个分区上。分区可以更细化,因为项目的数量可能远远多于标签,并且每个项目只有少数几个标签。这使得检索变得容易 (A1),并且可以在单个分区 (A2) 内强制执行唯一性。此外,单个分区可以告诉您一个项目是否匹配多个标签 (B2)。

      由于您一次只需要 一些 个给定标签(或多个标签)的项目 (B1),因此您可以按某种顺序一次查询一个分区,直到获得尽可能多的记录需要填写一页结果。您需要查询多少个分区取决于您有多少个分区、您要显示多少个结果以及标签的使用频率。每个分区在 tag_id 上都有自己的索引,以有效地回答此查询。

      您选择分区的顺序很重要,因为它会影响搜索结果的分组方式。如果排序不重要(即 B3 无关紧要),请随机选择分区,以免您的分区太热。如果排序很重要,您可以构造项目 id,以便它对与结果排序顺序相关的信息进行编码。然后适当的分区方案将注意这种编码。例如,如果结果是按受欢迎程度排序的 URL,那么您可以将顺序项目 ID 与该 URL(或任何类似的)的 Google Page Rank 分数结合起来。分区方案必须确保给定分区内的所有项目都具有相同的分数。查询将按分数选择分区,以确保首先返回更受欢迎的项目 (B3)。显然,这只允许一种排序,并且所涉及的属性应该是恒定的,因为它们现在是键的一部分并确定记录的分区。不过,这并不是一个真正的新限制,因为无论如何要支持各种排序或基于易失性属性的排序,以及分区数据并不容易。

      【讨论】:

      • 我不确定合并 item_id 的想法是否好。流行度随时间变化。在创建记录时也很难猜测流行度/页面排名/其他任何内容(那是应该计算组合 item_id 的时间)。
      • 是的,我同意并且通常不建议将值编码到 ID 中。流行度确实会随着时间而改变,但不会太快。如果在分区之间移动项目不是太困难,它仍然可能是一个不错的方法。您可以为TagMapping 中的每个项目使用另一个 ID,它可以更容易地随时间变化(而不是可能在许多其他地方使用的项目主键)。后台进程可以逐步重新计算这些新 ID 并重新组织 TagMapping 中的记录以反映流行度的变化。
      【解决方案3】:

      规则是按要查询的字段进行分区。否则,您将不得不查看所有分区。您确定只需要通过 tag_id 查询 Tag 表吗?我相信不会,您还需要按标签标题查询。这对于 Item 表来说并不那么明显,但是当其他用户为其分配标签时,您可能还想通过 URL 之类的内容进行查询以找到它的 item_id。

      但请注意,Tag 和 Item 表具有不可变的标题和 URL。这意味着您可以使用以下技术:

      1. 从标题(用于标签)或 URL(用于项目)中选择分区。
      2. 为此分区选择序列以生成 id。

      您要么使用 partition-localID 对作为全局标识符,要么使用不重叠的数字集。无论如何,现在您可以从 id 和 title/URL 字段计算分区。事先不知道分区的数量或担心它将来可能会改变?创建更多他们并加入小组,以便您将来重新组合他们。

      当然,你不能对 TagMapping 表做同样的事情,所以你必须复制。您需要通过 map_id、tag_id、item_id 来查询它,对吗?因此,即使没有分区,您也必须通过创建 3 个索引来复制数据。所以不同之处在于您对每个索引使用不同的分区(按不同的字段)。我认为没有理由担心。

      【讨论】:

        猜你喜欢
        • 2012-07-23
        • 1970-01-01
        • 2017-03-24
        • 2019-01-20
        • 2015-10-30
        • 2011-01-22
        • 2020-11-15
        • 1970-01-01
        • 2016-12-27
        相关资源
        最近更新 更多