如何实现标签系统

Sai*_*han 84 algorithm tagging system

我想知道实现标签系统的最佳方法是什么,比如SO上使用的标签系统.我在想这个但是我无法想出一个好的可扩展解决方案.

我正在考虑拥有一个基本的3表解决方案:拥有一张tags桌子,一张articles桌子和一张tag_to_articles桌子.

这是解决这个问题的最佳解决方案,还是有替代方案?使用这种方法,表格会在时间上变得非常大,而且对于搜索而言,我认为这不是太有效.另一方面,查询执行速度并不重要.

Nic*_*kis 114

我相信你会发现这篇博文有趣:标签:数据库模式

问题:您希望拥有一个数据库架构,您可以在其中使用任意数量的标签标记书签(或博客文章或其他内容).之后,您希望运行查询以将书签约束为联合或标记的交集.您还希望从搜索结果中排除(例如:减去)某些标记.

"MySQLicious"解决方案

在这个解决方案中,模式只有一个表,它是非规范化的.这种类型称为"MySQLicious解决方案",因为MySQLicious将del.icio.us数据导入具有此结构的表中.

在此输入图像描述在此输入图像描述

"search + webservice + semweb"的交集(AND)查询:

SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"
Run Code Online (Sandbox Code Playgroud)

联合(OR)查询"search | webservice | semweb":

SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"
Run Code Online (Sandbox Code Playgroud)

减去"search + webservice-semweb"的查询

SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"
Run Code Online (Sandbox Code Playgroud)

"天窗"解决方案

Scuttle将其数据组织在两个表格中.该表"scCategories"是"标签"-table,并且具有"书签"表的外键.

在此输入图像描述

"bookmark + webservice + semweb"的交集(AND)查询:

SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
HAVING COUNT( b.bId )=3
Run Code Online (Sandbox Code Playgroud)

首先,搜索所有书签 - 标签组合,其中标签是"书签","webservice"或"semweb"(c.category IN('bookmark','webservice','semweb')),然后只是书签搜索到的所有三个标签都被考虑在内(HAVING COUNT(b.bId)= 3).

Union(OR)查询"bookmark | webservice | semweb": 只需省略HAVING子句就可以了:

SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
Run Code Online (Sandbox Code Playgroud)

减号(排除)查询"bookmark + webservice-semweb",即:书签和web服务AND NOT semweb.

SELECT b. *
FROM scBookmarks b, scCategories c
WHERE b.bId = c.bId
AND (c.category IN ('bookmark', 'webservice'))
AND b.bId NOT
IN (SELECT b.bId FROM scBookmarks b, scCategories c WHERE b.bId = c.bId AND c.category = 'semweb')
GROUP BY b.bId
HAVING COUNT( b.bId ) =2
Run Code Online (Sandbox Code Playgroud)

退出HAVING COUNT会导致查询"bookmark | webservice-semweb".


"Toxi"解决方案

Toxi想出了一个三桌结构.通过表"tagmap",书签和标签是n-to-m相关的.每个标签可以与不同的书签一起使用,反之亦然.wordpress也使用这个DB模式.查询与"scuttle"解决方案中的查询完全相同.

在此输入图像描述

"bookmark + webservice + semweb"的交集(AND)查询

SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
HAVING COUNT( b.id )=3
Run Code Online (Sandbox Code Playgroud)

Union(OR)查询"bookmark | webservice | semweb"

SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
Run Code Online (Sandbox Code Playgroud)

减号(排除)查询"bookmark + webservice-semweb",即:书签和web服务AND NOT semweb.

SELECT b. *
FROM bookmark b, tagmap bt, tag t
WHERE b.id = bt.bookmark_id
AND bt.tag_id = t.tag_id
AND (t.name IN ('Programming', 'Algorithms'))
AND b.id NOT IN (SELECT b.id FROM bookmark b, tagmap bt, tag t WHERE b.id = bt.bookmark_id AND bt.tag_id = t.tag_id AND t.name = 'Python')
GROUP BY b.id
HAVING COUNT( b.id ) =2
Run Code Online (Sandbox Code Playgroud)

退出HAVING COUNT会导致查询"bookmark | webservice-semweb".

  • 很好的邮政坦克你. (3认同)
  • 这篇博客文章的作者在这里.该博客不再被Chrome阻止(愚蠢的wordpress漏洞,现在转移到tumblr).感谢将其转变为降价 (3认同)
  • 在帖子中提到的不同解决方案的性能比较链接? (2认同)

Joh*_*ohn 8

你的三表解决方案没有错.

另一种选择是限制可以应用于文章的标签数量(如SO中的5)并将这些标签直接添加到文章表中.

规范化DB有其优点和缺点,就像硬连接到一个表中的东西有利有弊.

没有什么说你做不到这两件事.它反对关系数据库范例重复信息,但如果目标是性能,你可能必须打破范式.


Juh*_*älä 6

您提议的三个表实现将用于标记.

但是,堆栈溢出使用不同的实现.它们以明文形式将标记存储到posts表中的varchar列,并使用全文索引来获取与标记匹配的帖子.例如posts.tags = "algorithm system tagging best-practices".我确信杰夫已经在某个地方提到了这个,但我忘了在哪里.

  • 这似乎超级低效.标签订单怎么样?还是相关的标签?(例如"过程"类似于"算法"或类似的东西) (4认同)