2012-07-12 64 views
0

我正在构建一个多站点平台,类似于StackExchange,它有多个社区使用相同的平台和共享数据。标签架构

用户可以像标记堆栈交换问题一样标记其内容。创建标签概念的最佳体系结构是什么?

我想过的一些小笔记是别名(同义词)的概念。另外我还想过,我希望标签可以跨站点共享(所以可以从另一个站点查看同一主题的内容),但另一方面,不同社区的上下文可能会有所不同。例如,计算机中的“图形”是一个数据结构,而数学则是其他的东西(只是我头顶的一个随机例子 - 不知道它是否重要)。

另外,如果我有英语和一个社区一个在法国...

你觉得呢?

+0

标签如何管理?在大多数站点(如StackOverflow)中,用户可以快速方便地创建标签。标签是否与正式类别相同,即严格在编辑过程中进行管理,还是他们是特设的,人群智慧型的东西? – 2012-07-12 17:11:06

+0

与Stack类似,他们只是键入单词。虽然我们可能需要一个最低水平来创建新的 – 2012-07-13 08:55:43

回答

0

我建议这样的模式:

ERD

你保持可用标签的列表,这些被应用到任何物品您使用的是标准的多对许多交集表标记。

要管理标记的同义词,请在可用标记表上使用渐近关系。这假设各种标签是同义词,其中一个被认为是“主要”标签。

可用标签有一个语言标志来表示英语或法语。如果您为加拿大政府或其他事情做这件事,并且需要确保所有内容都以两种语言出现,您可以在AVAILABLE_TAG上添加一个渐进的一对一(未显示),以链接相应的英文和法文标签。

要跨站点共享标签,请使用与SITE表的另一个多对多交叉点来显示哪些标签属于哪个站点。如果这些标签在每个网站上意味着不同的东西,我会避免在网站上共享标签。

1

做到在一个完全规范化的方式,你需要这样的事:

enter image description here

的MEANING_ITEM有以下指标:

  • {SITE_ID,MEANING_NO,ITEM_NO} - 为主键自动创建并支持使用给定标签高效搜索项目。
  • {ITEM_NO,SITE_ID,MEANING_NO} - 可以高效地查询相反的内容:“获取给定项目的标签”。

注意:如果您的DBMS支持它,请考虑clustering此表。集群表中的二级索引可能很昂贵(因为它们需要包含整个PK的副本并可能导致双重查找),但在这种情况下,两个索引都包含相同的字段(因此所有“额外”字段都已存在于次级索引),并且没有索引之外的字段,因此不需要进行双向查找。通过聚类,你只需要消除(无用的)表堆,而只剩下两个B树。

这种模式具有以下特性:

  • 两个标签和物品的部位特异性地识别和您查询默认站点特定的标签。如果您想查询标签名称而不考虑网站,只需在下面的查询中从WHERE子句中省略SITE_ID = ...即可。由于TAG_NAME处于TAG PK的领先优势,因此无需额外索引即可有效地满足无站点查询。
  • 项目不能标记来自“错误”网站的标签。我们使用标识关系,这些关系沿着“菱形”依赖关系的两个边缘向下传播SITE_ID,并合并到“菱形”(在MEANING_ITEM中)的底部,这就是我们保证的原因。
  • 标记同义词有效地表示(在同一站点内具有相同含义的标记被视为同义词)。如果我们试图在标签上实现M:N自我关系,那么就没有可能发生的各种异常情况。
  • 由于标签的含义是特定于站点的,所以同义词也是站点特定的。
  • 意义表是存储有关标记(如描述)的附加信息的自然地方,它将由所有同义词共享。

我们将如何处理同义词传递性?如果A,B和C是同义词,我们只是存储A-B和B-C,或者我们也存储A-C?我们如何执行它?如果我们不强制执行它,我们需要某种递归查询来选择所有依赖关系。我们需要为每个连接添加一行,浪费空间和性能。

要获得项目特定标记的任何,你需要执行一个类似的查询......

SELECT * 
FROM ITEM 
WHERE EXISTS (
    SELECT * 
    FROM TAG JOIN MEANING_ITEM ON 
     TAG.SITE_ID = MEANING_ITEM.SITE_ID 
     AND TAG.MEANING_NO = MEANING_ITEM.MEANING_NO 
    WHERE 
     TAG.SITE_ID = <site id> 
     AND TAG.NAME IN (<list of tags>) 
     AND ITEM.SITE_ID = MEANING_ITEM.SITE_ID 
     AND ITEM.ITEM_NO = MEANING_ITEM.ITEM_NO 
) 

注:我们完全可以忽略从JOIN到意义上面的查询 - JOIN所需的所有字段已经在TAG中。

对于有所有特定标记的项目,你需要一些计算,与此类似:

SELECT * 
FROM ITEM 
WHERE <number of tags> = (
    SELECT COUNT(DISTINCT TAG_NAME) 
    FROM TAG JOIN MEANING_ITEM ON 
     TAG.SITE_ID = MEANING_ITEM.SITE_ID 
     AND TAG.MEANING_NO = MEANING_ITEM.MEANING_NO 
    WHERE 
     TAG.SITE_ID = <site id> 
     AND TAG.NAME IN (<list of tags>) 
     AND ITEM.SITE_ID = MEANING_ITEM.SITE_ID 
     AND ITEM.ITEM_NO = MEANING_ITEM.ITEM_NO 
) 

现在这个貌似很多JOIN-ING的,但这种模式是优秀的对于聚簇(又名index-organized)表和covering带索引的查询。

您可能需要先考虑实际StackExchange的数据量,然后再出于性能原因考虑对该设计进行非规范化(例如,删除联结表并限制每个项目的标记数)。

在任何情况下,在进行任何特定设计之前都要测量实际的数据量。