我听说过几种实现标记的方法;使用TagID和ItemID之间的映射表(对我来说有意义,但是可以缩放吗?),向ItemID添加固定数量的可能的TagID列(似乎是个坏主意),将标签保持在逗号分隔的文本列中(声音疯狂但可以工作)。我什至听说有人建议使用稀疏矩阵,但是标签名称如何正常增长?

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

评论

好的,这是问题#20856,(几乎)相同的问题是#48475,至少在提出此问题后两周才提出。

另一个有趣的问题是“ SO如何实现标签?”

另一个有趣的问题是“您是否将它们国际化?如果可以,如何实现?”

有趣的比较(特定于Postgres):databasesoup.com/2015/01/tag-all-things.html

另请参见stackoverflow.com/questions/48475/database-design-for-tagging

#1 楼

正确地建立索引并在适当的数据库上运行外键的情况下,三个表(一个用于存储所有项目,一个用于所有标签,一个用于两者之间的关系)应该可以正常工作并且可以适当地扩展。

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID


评论


这就是所谓的“ Toxi”解决方案,您可以在这里找到有关它的更多信息:howto.philippkeller.com/2005/04/24/Tags-Database-schemas

– Pixel开发人员
09-6-28 at 12:41



此处未显示的一件事是“标签”表中的层次“标签”或类别。具有类别和子类别但需要灵活标记的网站通常需要这样做。例如,配方站点,汽车配件站点,企业目录等。这些类型的数据通常不只属于一个类别,因此标记是答案,但您需要使用诸如嵌套集模型或邻接表模型之类的东西。在您的代码表中。

– HK1
2011年1月21日20:50

我与HK1兼容,是否可以使用上述结构+表:TagGroup列:TagGropuId,标题表:标签列:TagID,标题,TagGroupId

–雷声
2011年2月11日在8:35

当我想将css列添加到表中时,我将css列添加到标签表中吗?

–阿弥陀佛
15年8月11日在9:19

@ftvs:链接再次断开,新链接为howto.philippkeller.com/2005/04/24/Tags-Database-schemas

–hansaplast
17年11月12日在7:02

#2 楼

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

使用两个表:

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

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


主要优点:首先,它使开发变得更加简单:在用于item的插入和更新的三表解决方案中,您必须查询Tag表以查看是否已经有条目。然后,您必须与新成员一起加入。这不是一件容易的事。

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

一个项目的所有标签:

3-Table:

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


2-Table:

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


标签云:

3-Table:

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


2-Table:

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:我将寻求两表解决方案。 (事实上​​,我要去。我找到了这篇文章,看看是否有反对它的有效论据。)

评论


“索引:ItemId,标题”是指每个索引还是包含两个索引的索引?

– DanMan
13年12月3日,11:23

通常有两个索引。不过,可能取决于您使用的数据库。

– Scheintod
2013年12月4日16:50

标签表中的ItemId和Tag是组合键吗?还是您也有PK?

– Rippo
2014年3月21日在18:41

这样,您将无法创建“未使用”的标签,因此必须在项目上执行“添加标签”功能。在另一种方法上,“添加标签”功能可以独立执行

– Gianluca Ghettini
17-4-22在11:42



@Quilang。我仍然相信这取决于您的工作:)我在不同项目中以两种方式实现了它。在我的最后一个中,我最终得到了3表解决方案,因为我需要一个“标签类型”(或标签上的其他元信息),并且可以重用标签的近亲:参数。但是在同一项目中,我恰好使用了这种方法来获得更近的表亲:标志(例如“卖”,“新”,“热”)

– Scheintod
18-10-24在6:56



#3 楼

如果您使用的是支持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很高兴看到一些NoSQL实现。

– Xeoncross
2011-3-18在16:24

@NickRetallack链接无效。如果可以,请更新此答案。

–xralf
2012-2-18在10:21

好的,我用一个链接替换为archive.org

–尼克·雷塔拉克(Nick Retallack)
2012年2月20日下午4:47

#4 楼

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

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

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

评论


您是否知道没有找到单词变体的全文搜索引擎?例如,要搜索退货书?另外,您如何处理“ c ++”之类的标签?例如,SQL Server将删除索引中的加号。谢谢。

–乔纳森·伍德
2011-1-18的1:41

尝试Sphinx-sphinxsearch.com

–罗马
2011-2-9 13:45

这个由3部分组成的教程可能对那些打算走这条路线(全文搜索)的人有用。它使用PostgreSQL本机工具:shisaa.jp/postset/postgresql-full-text-search-part-1.html

–将
14年5月14日在21:42

在性能方面,这是否比所选答案更好?

–user1642018
17-10-22在7:49

如何使用varchar 255,逗号分隔的标签并在其上添加kfull文本索引进行存储?

–user1642018
17-10-22在7:50

#5 楼

我一直将标签放在单独的表中,然后有一个映射表。当然,我也从来没有做过任何大规模的事情。

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

评论


如果您不使用映射表,这将更加容易:)

– Scheintod
2013年9月27日19:11在

#6 楼

我建议采用以下设计:
项目表:
Itemid,taglist1,taglist2
这将是快速的,并且易于在项目级别保存和检索数据。

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

现在,在搜索标签商品时,它将会非常快。

评论


en.wikipedia.org/wiki/First_normal_form尽管对此有例外,您可以将其去规范化,但此处不行

– Dheeraj
15年12月24日在6:27