我听说过几种实现标记的方法; 使用TagID和ItemID之间的映射表(对我有意义,但它是否可以缩放?),向ItemID添加固定数量的可能TagID列(似乎是一个坏主意),将标记保留在逗号分隔的文本列中(声音疯了,但可以工作).我甚至听过有人推荐稀疏矩阵,但那么标签名称如何优雅地增长?
我错过了标签的最佳做法吗?
三个表(一个用于存储所有项目,一个用于所有标记,一个用于两者之间的关系),正确编制索引,外键设置在适当的数据库上运行,应该可以正常工作并正确缩放.
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
这有一些主要优点:
首先,它使开发变得更加简单:在用于插入和更新的三表解决方案中,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
但也有一些缺点:它可能需要在数据库中占用更多空间(这可能导致更多的磁盘操作更慢)并且没有规范化可能导致不一致.
size参数不是那么强大,因为标签的本质是它们通常非常小,所以尺寸增加不是很大.有人可能会争辩说,标签标题的查询在一个只包含每个标签一次的小表中要快得多,这肯定是正确的.但是考虑到不必加入的节省以及你可以为它们建立一个好的索引的事实可以很容易地弥补这一点.这当然在很大程度上取决于您使用的数据库的大小.
不一致的论点也有点没有实际意义.标签是自由文本字段,没有预期的操作,如'重命名所有标签'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运行此命令将按标记名称对结果进行分组,甚至返回遇到标记的次数计数.它与计算文本中单词的出现次数非常相似.
使用单个格式化文本列[1]存储标记,并使用功能强大的全文搜索引擎对其进行索引.否则,在尝试实现布尔查询时,您将遇到扩展问题.
如果需要有关标记的详细信息,可以在增量维护的表中跟踪它,也可以运行批处理作业来提取信息.
[1]有些RDBMS甚至提供了一种原生数组类型,它可能更适合存储而不需要解析步骤,但可能会导致全文搜索出现问题.
我总是将标签保存在一个单独的表中,然后有一个映射表.当然,我从未做过大规模的任何事情.
拥有"标签"表和地图表使得生成标签云非常简单,因为您可以轻松地将SQL组合在一起以获取标签列表,其中包含每个标签使用频率的计数.