324

我听说过几种实现标记的方法;使用 TagID 和 ItemID 之间的映射表(对我来说很有意义,但它可以扩展吗?),向 ItemID 添加固定数量的可能 TagID 列(似乎是个坏主意),将标签保留在逗号分隔的文本列中(听起来疯狂但可以工作)。我什至听说有人推荐一个稀疏矩阵,但是标签名称如何优雅地增长?

我错过了标签的最佳实践吗?

4

6 回答 6

448

三张表(一张用于存储所有项目,一张用于所有标签,一张用于两者之间的关系),正确索引,外键设置在正确的数据库上运行,应该可以正常工作并正确扩展。

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID
于 2008-08-21T19:22:44.013 回答
95

通常我会同意 Yaakov Ellis 但在这种特殊情况下还有另一个可行的解决方案:

使用两个表:

Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID

Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title

这有一些主要优点:

首先,它使开发变得更加简单:在插入和更新的三表解决方案中,item您必须查找Tag表以查看是否已经存在条目。然后你必须和他们一起加入新的。这不是一项简单的任务。

然后它使查询更简单(也许更快)。您将执行三个主要的数据库查询:Tags为一个输出全部Item,绘制一个标签云并为一个标签标题选择所有项目。

一件物品的所有标签:

3-表:

SELECT Tag.Title 
  FROM Tag 
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 WHERE ItemTag.ItemID = :id

2-表:

SELECT Tag.Title
FROM Tag
WHERE Tag.ItemID = :id

标签云:

3-表:

SELECT Tag.Title, count(*)
  FROM Tag
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 GROUP BY Tag.Title

2-表:

SELECT Tag.Title, count(*)
  FROM Tag
 GROUP BY Tag.Title

一个标签的项目:

3-表:

SELECT Item.*
  FROM Item
  JOIN ItemTag ON Item.ItemID = ItemTag.ItemID
  JOIN Tag ON ItemTag.TagID = Tag.TagID
 WHERE Tag.Title = :title

2-表:

SELECT Item.*
  FROM Item
  JOIN Tag ON Item.ItemID = Tag.ItemID
 WHERE Tag.Title = :title

但是也有一些缺点:它可能在数据库中占用更多空间(这可能导致更多的磁盘操作更慢)并且它没有标准化,这可能导致不一致。

大小的论点不是那么强,因为标签的本质是它们通常很小,所以大小的增加并不大。有人可能会争辩说,在一个只包含每个标签一次的小表中,对标签标题的查询要快得多,这当然是正确的。但是考虑到不必加入的节省以及您可以在它们上建立良好索引的事实可以很容易地弥补这一点。这当然很大程度上取决于您使用的数据库的大小。

不一致的论点也有点没有实际意义。标签是自由文本字段,没有像“将所有标签“foo”重命名为“bar”这样的预期操作。

所以 tldr:我会选择两表解决方案。(事实上​​我要去。我找到了这篇文章,看看是否有反对它的有效论据。)

于 2013-09-20T18:37:33.070 回答
39

如果您使用的是支持 map-reduce 的数据库,例如 couchdb,则将标签存储在纯文本字段或列表字段中确实是最好的方法。例子:

tagcloud: {
  map: function(doc){ 
    for(tag in doc.tags){ 
      emit(doc.tags[tag],1) 
    }
  }
  reduce: function(keys,values){
    return values.length
  }
}

使用 group=true 运行此命令将按标签名称对结果进行分组,甚至返回遇到该标签的次数的计数。这与计算一个单词在 text 中的出现非常相似。

于 2008-09-07T19:41:11.363 回答
13

使用单个格式化的文本列 [1] 来存储标签,并使用功能强大的全文搜索引擎对其进行索引。否则,在尝试实现布尔查询时会遇到扩展问题。

如果您需要有关您拥有的标签的详细信息,您可以在增量维护的表中跟踪它,或者运行批处理作业来提取信息。

[1] 一些 RDBMS 甚至提供了本机数组类型,它可能更适合存储,因为不需要解析步骤,但可能会导致全文搜索出现问题。

于 2008-09-07T11:47:34.983 回答
9

我总是将标签保存在一个单独的表中,然后有一个映射表。当然,我也从来没有做过大规模的事情。

拥有一个“标签”表和一个映射表使得生成标签云等变得非常简单,因为您可以轻松地将 SQL 放在一起以获取标签列表以及每个标签的使用频率。

于 2008-08-21T19:23:32.360 回答
-2

我建议采用以下设计:项目表:Itemid、taglist1、taglist2
这将很快,并且可以轻松地在项目级别保存和检索数据。

并行构建另一个表:标签标签不会使标签成为唯一标识符,如果您在包含 100 个项目的第二列中的空间不足,则创建另一行。

现在,在为标签搜索项目时,它会非常快。

于 2015-11-28T09:51:15.113 回答