我听说过一些实现标签的方法;使用TagID和ItemID之间的映射表(对我来说有意义,但它是否缩放?),向ItemID添加固定数量的可能的TagID列(似乎是个坏主意),在文本列中保留逗号分隔的标签(听起来很疯狂,但可以工作)。我甚至听说有人建议使用稀疏矩阵,但是标签名如何优雅地增长呢?
我是否错过了标签的最佳实践?
我听说过一些实现标签的方法;使用TagID和ItemID之间的映射表(对我来说有意义,但它是否缩放?),向ItemID添加固定数量的可能的TagID列(似乎是个坏主意),在文本列中保留逗号分隔的标签(听起来很疯狂,但可以工作)。我甚至听说有人建议使用稀疏矩阵,但是标签名如何优雅地增长呢?
我是否错过了标签的最佳实践?
当前回答
通常情况下,我会同意Yaakov Ellis的观点,但在这种特殊情况下,还有另一种可行的解决方案:
使用两个表:
Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID
Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title
这有一些主要的优势:
首先,它使开发变得更加简单:在插入和更新项目的三表解决方案中,您必须查找Tag表,以查看是否已经有条目。然后你必须加入新的。这不是一项简单的任务。
然后,它使查询更简单(也许更快)。有三个主要的数据库查询,你将做:输出一个项目的所有标签,绘制标签云和选择一个标签标题的所有项目。
一个项目的所有标签:
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
但是也有一些缺点:它可能会占用数据库中的更多空间(这可能会导致更慢的更多磁盘操作),并且它不是标准化的,这可能会导致不一致。
The size argument is not that strong because the very nature of tags is that they are normally pretty small so the size increase is not a large one. One could argue that the query for the tag title is much faster in a small table which contains each tag only once and this certainly is true. But taking in regard the savings for not having to join and the fact that you can build a good index on them could easily compensate for this. This of course depends heavily on the size of the database you are using.
前后矛盾的论点也有点毫无意义。标签是自由文本字段,没有像“将所有标签“foo”重命名为“bar”这样的操作。
tldr:我会选择双表解决方案。(事实上,我正要去。我找到了这篇文章,看看是否有有效的理由反对它。)
其他回答
如果您正在使用支持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运行该命令将根据标记名称对结果进行分组,甚至返回遇到该标记的次数的计数。这与计算一个单词在文本中的出现次数非常相似。
三个表(一个用于存储所有项,一个用于存储所有标记,一个用于存储两者之间的关系),在适当的数据库上正确地建立索引,并设置外键,应该能够正常工作并适当地扩展。
Table: Item
Columns: ItemID, Title, Content
Table: Tag
Columns: TagID, Title
Table: ItemTag
Columns: ItemID, TagID
通常情况下,我会同意Yaakov Ellis的观点,但在这种特殊情况下,还有另一种可行的解决方案:
使用两个表:
Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID
Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title
这有一些主要的优势:
首先,它使开发变得更加简单:在插入和更新项目的三表解决方案中,您必须查找Tag表,以查看是否已经有条目。然后你必须加入新的。这不是一项简单的任务。
然后,它使查询更简单(也许更快)。有三个主要的数据库查询,你将做:输出一个项目的所有标签,绘制标签云和选择一个标签标题的所有项目。
一个项目的所有标签:
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
但是也有一些缺点:它可能会占用数据库中的更多空间(这可能会导致更慢的更多磁盘操作),并且它不是标准化的,这可能会导致不一致。
The size argument is not that strong because the very nature of tags is that they are normally pretty small so the size increase is not a large one. One could argue that the query for the tag title is much faster in a small table which contains each tag only once and this certainly is true. But taking in regard the savings for not having to join and the fact that you can build a good index on them could easily compensate for this. This of course depends heavily on the size of the database you are using.
前后矛盾的论点也有点毫无意义。标签是自由文本字段,没有像“将所有标签“foo”重命名为“bar”这样的操作。
tldr:我会选择双表解决方案。(事实上,我正要去。我找到了这篇文章,看看是否有有效的理由反对它。)
我总是把标签放在一个单独的表中,然后有一个映射表。当然,我也从来没有做过真正大规模的事情。
拥有一个“标签”表和一个映射表使得生成标签云变得非常简单,因为您可以轻松地将SQL组合在一起以获得一个标签列表,其中包含每个标签的使用频率。
我建议设计如下: 项目表: Itemid, taglist1, taglist2 这将是快速和容易的保存和检索数据的项目级别。
并行构建另一个表: 标签 标签 不要让标签唯一的标识符,如果你用完了第二列的空间,其中包含100个项目,创建另一行。
现在,当搜索项目的标签,这将是超级快。