<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>.::灵狼天::. &#187; Tag</title>
	<atom:link href="http://icyleaf.com/tag/tag/feed/" rel="self" type="application/rss+xml" />
	<link>http://icyleaf.com</link>
	<description>icyleaf&#039;s blog - 心外无理，心外无物，心外无事</description>
	<lastBuildDate>Tue, 13 Dec 2011 02:34:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>标签(Tag)的数据库设计</title>
		<link>http://icyleaf.com/2008/06/tags-database-schemas/</link>
		<comments>http://icyleaf.com/2008/06/tags-database-schemas/#comments</comments>
		<pubDate>Sat, 21 Jun 2008 02:14:27 +0000</pubDate>
		<dc:creator>icyleaf</dc:creator>
				<category><![CDATA[网络开发]]></category>
		<category><![CDATA[DB]]></category>
		<category><![CDATA[schemas]]></category>
		<category><![CDATA[Tag]]></category>

		<guid isPermaLink="false">http://www.icyleaf.cn/?p=207</guid>
		<description><![CDATA[原文来自：Then each went to his own home 原文作者：Philipp Keller 中文翻译：icyleaf 译者注：本文在涉及到专业术语或者译者表达不明白的地方均会保留原英文。 最近，在del.icio.us mailinglist（译者按：应该是美味书签的讨论版块。以下del.icio.us翻译为美味书签）上面发了一个问题：“有人知道美味书签的数据库设计吗？”。之后我得到了一些回复，所以我想把这部分东西的知识分享给大家。 疑问 当你要为一个书签添加你认为需要的一个或多个标签时（或日志或其他）其数据库是如何设计的？然后，执行查询时取消这些书签中标签的合集（union）或交集（intersection）。也能从搜索结果中减少一些标签。 大致有三种不同的解决方案：（注意：如果你开发了一个网站使得任何人都可以添加标签，而且是一个较大规模的网站则请务必看下其作者写的另外一篇文章：标签系统的性能测试） “MySQLicious” 方法(solution) 在这个方法中仅架构了一个表，它是去规范化（denormalized）表。 这个类型被叫做“MySQLicious 方法(solution)”，因为MySQLicious使用这种结构可以把美味书签的数据导入到一个表中。 译者注：MySQLicious是一个把del.icio.us书签镜像到MySQL数据库中的工具。 交集(AND) 查询方式： “search+webservice+semweb”: SELECT * FROM `delicious` WHERE tags LIKE "%search%" AND tags LIKE "%webservice%" AND tags LIKE &#8230; <a href="http://icyleaf.com/2008/06/tags-database-schemas/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>原文来自：<a href="http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html" target="_self">Then each went to his own home</a><br />
原文作者：<a href="http://www.pui.ch/phred/about" target="_self">Philipp Keller</a><br />
中文翻译：<a href="http://www.icyleaf.cn" target="_self">icyleaf</a></p>
<p>译者注：本文在涉及到专业术语或者译者表达不明白的地方均会保留原英文。</p>
<p>最近，在<a href="http://lists.del.icio.us/pipermail/discuss/2005-April/002827.html">del.icio.us mailinglist</a>（译者按：应该是美味书签的讨论版块。以下del.icio.us翻译为<strong>美味书签</strong>）上面发了一个问题：“有人知道美味书签的数据库设计吗？”。之后我得到了一些回复，所以我想把这部分东西的知识分享给大家。</p>
<h2>疑问</h2>
<p>当你要为一个书签添加你认为需要的一个或多个标签时（或日志或其他）其数据库是如何设计的？然后，执行查询时取消这些书签中标签的合集（<a href="http://en.wikipedia.org/wiki/Union_%28set_theory%29">union</a>）或交集（<a href="http://en.wikipedia.org/wiki/Intersection_%28set_theory%29">intersection</a>）。也能从搜索结果中减少一些标签。</p>
<p>大致有三种不同的解决方案：（<strong>注意</strong>：如果你开发了一个网站使得任何人都可以添加标签，而且是一个较大规模的网站则请务必看下其作者写的另外一篇文章：<a href="http://www.pui.ch/phred/archives/2005/06/tagsystems-performance-tests.html" target="_self">标签系统的性能测试</a>）<br />
<span id="more-207"></span></p>
<h2>“MySQLicious” 方法(solution)</h2>
<p>在这个方法中仅架构了一个表，它是去规范化（<a href="http://en.wikipedia.org/wiki/Denormalization">denormalized</a>）表。</p>
<p>这个类型被叫做“MySQLicious 方法(solution)”，因为MySQLicious使用这种结构可以把美味书签的数据导入到一个表中。</p>
<p>译者注：MySQLicious是一个把del.icio.us书签镜像到MySQL数据库中的工具。</p>
<h2><img class="alignright" style="float: left;" src="http://www.pui.ch/phred/modules/mysqlicious_structure.png" alt="" /></h2>
<p><img src="http://www.pui.ch/phred/modules/mysqlicious_data.png" alt="" width="373" height="172" /></p>
<h3><span style="color: #800000;">交集(AND)</span></h3>
<p>查询方式： “search+webservice+semweb”:</p>
<pre lang="sql" line="1" colla="+">
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"
</pre>
<h3><span style="color: #800000;">合集(OR)</span></h3>
<p>查询方式： “search|webservice|semweb”:</p>
<pre lang="sql" line="1" colla="+">
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"
</pre>
<h3><span style="color: #800000;">减少(Exclusion)</span></h3>
<p>查询方式： “search+webservice-semweb”</p>
<pre lang="sql" line="1" colla="+">
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"
</pre>
<h3><span style="color: #800000;">结论</span></h3>
<p>优点：</p>
<ul>
<li>只用一个表。</li>
<li>查询方式简单易懂。</li>
<li>一次就能获得全文搜索结果，可能速度快一些。</li>
<li>我猜测查询在基于<a href="http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html#comment-57" target="_self">良好</a>的<a href="http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html#comment-62" target="_self">参数</a>下是相当的 <span style="text-decoration: line-through;">快（<a href="http://www.petercooper.co.uk/archives/000648.html">Peter Cooper</a>的博客也提到：去规范化！去规范化！去规范化！）</span> 慢的。全文搜索会稍微提速，我做了一个<a href="http://www.pui.ch/phred/archives/2005/06/tagsystems-performance-tests.html" target="_self">我的配置测试</a>来验证它。</li>
<li><a href="http://www.pui.ch/phred/archives/2005/05/tags-with-mysql-fulltext.html" target="_self">在我随后的日志交待使用MySQL fulltext出来有关标签的事情</a>。</li>
</ul>
<p>缺点：</p>
<ul>
<li>每个书签的标签数量是有限的。通常情况下是在数据库中使用一个256字节的域（VCHAIR），否则，假设你用<strong>Text</strong>或类似的域，则速度将会慢下来。</li>
<li>如果你注意了（就像<a href="http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html#comment-63">Patrice</a>那样）你会发现当你以“websearch”使用<strong>Like “%search</strong>”搜索标签时它也能搜索到，当你修改并使用<strong>Like “%search%</strong>”时你最终必须使用一个混乱的解决方法：在标签头添加一个空格，这样才能使其工作。</li>
</ul>
<h2><a name="scuttle"><img class="alignright" style="float: right;" src="http://www.pui.ch/phred/modules/scuttle_structure.png" alt="" width="206" height="138" />“Scuttle” 方法(solution)</a></h2>
<p>分离（Scuttle）字段，并归类到两个表中。右图表“scCategories”是一个标签表，通过一个外来的ID链接书签表。</p>
<h3><span><span style="color: #800000;">交集(AND)</span></span></h3>
<p>查询方式：“bookmark+webservice+semweb”:</p>
<pre lang="sql" line="1" colla="+">
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
</pre>
<p>首先，当搜索的标签为“bookmark”，“webservice“或“semweb”（例如：<strong><code>c.category IN ('bookmark', 'webservice', 'semweb')</code></strong>）时所有名为&#8221;bookmark&#8221;的标签都会被搜索，然后所有包含这三个标签的书签将筛选出来 (<strong><code>HAVING COUNT(b.bId)=3</code></strong>).</p>
<h3><span><span style="color: #800000;">合集(OR)</span></span></h3>
<p>查询方式：“bookmark|webservice|semweb”:<br />
Just leave out the <code>HAVING</code> clause and you have union:</p>
<pre lang="sql" line="1" colla="+">
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
</pre>
<h3><span style="color: #800000;">减少(Exclusion)</span></h3>
<p>查询方式：“bookmark+webservice-semweb”，意味着：bookmark AND webservice AND NOT semweb.</p>
<pre lang="sql" line="1" colla="+">
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
</pre>
<p>省略掉 <strong><code>HAVING COUNT</code></strong> 会导致搜索方式变为“bookmark|webservice-semweb”.<br />
信息来源：<a href="http://www.metafilter.com/user/26222">Rhomboid</a>写的<a href="http://ask.metafilter.com/mefi/34897#544185">helping me out with this query</a>.</p>
<h3><span><span style="color: #800000;">结论</span></span></h3>
<p>我猜测这个解决方案主要有利点是使得他更正常化，比第一个解决方案比较而言，好处在于可以为每一个书签添加无限数量的标签。</p>
<h2><a name="toxi">“Toxi” 方法(solution)</a></h2>
<h2><a name="toxi"><img class="alignright" style="float: right;" src="http://www.pui.ch/phred/modules/toxi_structure.png" alt="" width="330" height="109" /></a></h2>
<p><a href="http://toxi.co.uk/">Toxi</a> 提出了一个三个表的结构，通过表”tagmap“的书签和标签的n-to-m关联。每一个标签都可以在不同的书签一期使用，反之亦然。这种数据库结构也被用在<a href="http://wordpress.org/">WordPress</a>之中。</p>
<h3><span><span><span style="color: #800000;">交集(AND)</span></span></span></h3>
<p>查询方式：“bookmark+webservice+semweb”</p>
<pre lang="sql" line="1" colla="+">
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
</pre>
<h3><span><span><span style="color: #800000;">合集(OR)</span></span></span></h3>
<p>查询方式：“bookmark|webservice|semweb”</p>
<pre lang="sql" line="1" colla="+">
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
</pre>
<h3><span><span style="color: #800000;">减少(Exclusion)</span></span></h3>
<p>查询方式：“bookmark+webservice-semweb”，意味：bookmark AND webservice AND NOT semweb.</p>
<pre lang="sql" line="1" colla="+">
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
</pre>
<p>省略掉 <strong><code>HAVING COUNT</code></strong> 会导致搜索方式变为“bookmark|webservice-semweb”.<br />
信息来源：<a href="http://www.metafilter.com/user/26222">Rhomboid</a>写的<a href="http://ask.metafilter.com/mefi/34897#544185">helping me out with this query</a>.</p>
<h3><span><span><span><span style="color: #800000;">结论</span></span></span></span></h3>
<p>优点：</p>
<ul>
<li>可以为每个标签节省额外的信息（描述，分类等）</li>
<li>这是一个最正常化的解决方案（即，第三范式：<a href="http://en.wikipedia.org/wiki/3NF">3NF</a>）</li>
</ul>
<p>缺点：</p>
<ul>
<li>当修改或删除书签后，需要删除中间表的相应数据（When altering or deleting bookmarks you can end up with tag-orphans）。</li>
</ul>
<p>如果你想要更复杂的查询，比如”<strong>(bookmarks OR bookmark) AND (webservice or WS) AND NOT (semweb or semanticweb)</strong>“这样的查询语句，我建议参见以下查询/计算过程：</p>
<ol>
<li>为每一个标签出现在你的”“tag-query”时执行一个查询（Run a query for each tag appearing in your “tag-query”）：<strong><code>SELECT b.id FROM tagmap bt, bookmark b, tag t WHERE bt.tag_id = t.tag_id AND b.id = bt.bookmark_id AND t.name = "semweb"</code></strong></li>
<li>把每一个编号集从结果中导到一个数值里面（使用你喜欢的编码语言），这样可以缓存你想要的数组。</li>
<li>使用合集或交集或其他方式限制数组。</li>
</ol>
<p>通过这种方式，你也可以查询<code>"<strong>(del.icio.us|delicious)+(semweb|semantic_web)-search</strong>"，这种类型的查询（即，括号内）利用去规范化的</code>“MySQLicious solution”<code>不能这样做。<br />
这是最灵活的数据结构和我猜想它的效果相当好（即，使用一些缓存技术）。</code></p>
<p><strong>2006年5月更新</strong>：这篇文章获得了大家的注视。我真的不是为此而准备的！看来大家不断的提到了他，甚至一些网站转载我的文章，我认为，这些不同方式的理论的知识应该归功于：<a href="http://nanovivid.com/projects/mysqlicious/">MySQLicious</a>, <a href="http://sourceforge.net/projects/scuttle/">scuttle</a>, <a href="http://toxi.co.uk/">Toxi</a>以及所有参与并贡献的评论者（请务必阅读！）</p>
<p>p.s.  感谢<a href="http://toxi.co.uk/">Toxi</a>发给我关于三个表结构的疑问，Benjamin Reitzammer为我指点的<a href="http://laughingmeme.org/archives/002918.html" target="_self">文章</a>（一个很好的标签查询参考）和powerlinux提供的<a href="http://sourceforge.net/projects/scuttle/">scuttle</a>指引。</p>
<h2>扩展阅读</h2>
<ul><ins datetime="2006-05-01T09:20:11+00:00"></p>
<li><ins datetime="2005-06-28T09:01:13-02:00"><a href="http://lists.tagschema.com/mailman/listinfo/tagdb">Taglist: a mailing list dedicated to schemas with tagging</a></ins></li>
<li><ins datetime="2005-06-26T15:02:02-02:00"><a href="http://tagschema.com/blogs/tagschema/">Tagschema: A blog dedicated to tagging schemas</a></ins></li>
<li><a href="http://www.bigbold.com/snippets/tags/tagging">Tag-related Queries on Snippets</a></li>
<li><ins datetime="2005-05-08T18:28:16-02:00"><a href="http://www.getluky.net/freetag/">Freetag</a> is a php “library” with which you can add tags to whatever object you like. It actually uses the “toxi schema”.</ins></li>
<li><ins datetime="2005-05-10T09:45:38-02:00">Hammy <a href="http://hellojoseph.com/tags-howto.php">gives an insight</a> how he did his tagging system with “less DB and more code” (that is: regular expressions), interesting!</ins></li>
<li>Brad Choate <a href="http://bradchoate.com/weblog/2004/10/06/delicious">has got some ideas</a> which tag queries should be possible</li>
<li>Feedmaker has written <a href="http://blog.feedmarker.com/2005/04/26/tagging-in-mysql/">a sort of reply to this article</a></li>
<p></ins></ul>
]]></content:encoded>
			<wfw:commentRss>http://icyleaf.com/2008/06/tags-database-schemas/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

