如何为分区标记系统设计数据存储?

问题描述:

如何为大型标记系统(如digg或delicious)设计数据存储?如何为分区标记系统设计数据存储?

关于它,已经有discussion了,但是关于*数据库。由于数据应该会增长,因此我们需要将数据快速分割成多个分片。所以,问题变成:如何为分区标记系统设计数据存储?

的标签系统主要有3个表:

Item (item_id, item_content) 

Tag (tag_id, tag_title) 

TagMapping(map_id, tag_id, item_id) 

这工作正常,找到了给定标签的所有项目,并找出所有标签为给定的项目,如果该表存储在一个数据库实例。如果我们需要将数据分区为多个数据库实例,那并不容易。

对于表项目,我们可以将其内容与其关键字item_id分区。对于表标签,我们可以将其内容与其关键字tag_id分区。例如,我们想要将表标记划分为K个数据库。我们可以简单地选择号码(tag_id%K)数据库来存储给定的标签。

但是,如何分区表TagMapping

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

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

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

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

查找标签某个商品

A1。您要一次显示全部的某个给定物品的标签

A2。你要确保所有项目的标签是对于给定的标签

B1独特

寻找项目。您一次需要某个的某个标签的项目(填充搜索结果的页面)

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

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

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

因为你只有一次(B1),可以查询一个分区以某种顺序时间,直到你有需要填补尽可能多的记录需要对于给定的标签的项目(或标签)的一些结果页面。您需要查询多少个分区取决于您拥有多少个分区,要显示多少个结果以及使用多少个标签。每个分区在tag_id上都有自己的索引来有效地回答这个查询。

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

+0

我不确定组合item_id的想法是否好。人气随时间变化。在创建记录时,也很难猜测受欢迎程度/页面排名/无论什么时候(这是当时,当计算联合item_id时)。 – Wacek 2010-04-24 11:18:27

+0

是的,我同意并且通常不会推荐将编码值编入ID中。人气会随着时间而改变,但不会太快。如果在分区之间移动项目不是太困难,它仍然可能是一个好方法。您可以为'TagMapping'中的每个项目使用另一个ID,以便随时更改(而不是可能在许多其他地方使用的项目主键)。后台进程可以递增地重新计算这些新ID并在“TagMapping”中重新组织记录以反映流行度的变化。 – 2010-04-24 15:46:16

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

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

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

您可以使用partition-localID对作为全局标识符或使用非重叠数字集。无论如何,现在你可以从ID和标题/ URL字段中计算分区。事先不知道分区数量还是未来可能会改变?创建更多,并加入小组,以便将来可以重新组合。

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

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

你说的是DB的分布,通常这个问题大多是同步的问题。阅读通常可以完成90%的工作,可以在复制的数据库上完成。问题是如何更新一个数据库并保持一致将所有其他和不杀的性能。这取决于你的场景细节。

另一种可能性是像你问的那样对所有数据进行分区而不重叠。您可能会按用户标识或主题标识进行分区。如果按主题标识进行分区,则一个数据库可以引用所有主题并只告诉哪个专用数据库保存了数据。然后您可以查询正确的一个。由于您使用ID进行分区,因此与该主题相关的所有信息都可能位于该专用数据库中。您也可以通过语言国家分区为国际网站。

最后但并非最不重要的一点,您可能最终将两者混合:一些不重叠的数据和一些重叠(复制)的数据。首先找到通常的操作,然后找到如何在一个数据库中尽可能少地查询这些操作。 PS:不要忘记缓存,它会比分布式数据库节省更多。