我有一个照片网站,我想支持标签,因为我的原始类别分组开始失败(一些照片是家庭和假期,或学校和朋友)。是否有商定的标记数据库架构?
我仍然希望支持将照片作为相册的一部分。
现在我有几张桌子:
照片
相册
答案 0 :(得分:23)
有各种有效的模式,每种模式都有自己的性能影响,因为随着标记项目数量的增长,您需要使用常见查询:
就个人而言,我喜欢有一个标签表和一个链接表,它将标签与项目关联,因为它是非规范化的(没有重复的标签名称),我可以在链接表中存储其他信息(例如标记项目时)必要时。
如果您感觉活泼并且想要通过在标签表中存储使用计数所需的额外数据维护成本,或者存储在项目表本身中使用的标签名称,您还可以添加一些非规范化数据避免点击每个项目的链接表和标签表,这对于显示包含所有标签的多个项目和简单的标签版本控制非常有用...如果您遇到这种情况;)
答案 1 :(得分:11)
我在没有很多用户的小型系统中完成了这项工作,但我之前想知道是否有“接受”的方式来管理标签。在阅读了insin发布的链接以及许多关于标记的其他博客文章后,似乎可接受的方法是将其完全标准化存储,并在数据集过大时缓存某些内容。
由于这是一个多关系(每个标签可以属于任意数量的照片 - 每张照片都可以有很多标签),关系数据库理论让你创建一个照片表,一个标签表和一个交叉引用表来链接它们。
photos
photoid
caption
filename
date
tags
tagid
tagname
phototags
photoid
tagid
这有从大型数据集中选择的扩展问题,但所有较不规范化的模式也是如此(例如,文本字段的排序和过滤可能总是比使用整数慢)。如果你的成长与美味甚至StackOverflow一样大,你可能需要对标签集进行一些缓存。
您必须面对的另一个问题是标签规范化问题。这与数据库规范化没有任何关系 - 它只是确保(例如)“StackOverflow”,“stackoverflow”和“stack overflow”标记是相同的。很多地方不允许空白或自动剥离空白。有时你会看到标点符号相同的东西 - 使“StackOverflow”与“Stack-Overflow”相同。自动小写是非常标准的。你甚至可以看到特殊情况规范化 - 比如使“c#”与“csharp”相同。
快乐标记!
答案 2 :(得分:2)
我想到了这样的事情:添加这两个表
<强>代码
<强> PhotoTags 强>
您也可以将此扩展到相册,并在相册和标签之间设置交叉表。
答案 3 :(得分:2)
我建议看看已经建立的开源软件是如何实现的。例如,Gallery将其元数据存储在数据库中,就像您一样,而且非常丰富。
但是,我不认为你会找到一个“标准”架构。我能想到的最接近的是EXIF元数据格式,它嵌入在图像文件中(通过相机等)。答案 4 :(得分:0)
如果您想要拥有数百万条记录的真实性能,您可以将标签存储在一个字段中,使用全文索引/搜索守护程序(如sphinxsearch)将逗号分隔和检索记录存储在一起。您需要添加的是一个表格,其中列出了所有带有计数值的标签,以了解它们附加到项目的频率。
我知道这不是通常的方式,而是比纯数据库解决方案更复杂,但搜索标签相关项目真的非常快。
您也可以使用数据库引擎的全文搜索功能,但是当有大量记录时,大多数引擎都会变慢。
如果这是一个小项目,你可以按照自己的方式,接缝良好和正确的方式去做。但我会与你分享这个其他解决方案。你怎么看?
答案 5 :(得分:0)
在我的应用程序BugTracker.NET中,我假设不会有太多错误。也许成千上万,但不是数千万。这个假设允许我缓存标签和他们引用的项目的ID。
在数据库中,标签在输入时以错误的形式存储在逗号分隔的文本字段中。
当添加或更改标记字段时,会启动一个后台线程,选择所有bugid及其标记,解析文本,构建一个映射,其中键是标记,值是所有id的列表有那个标签。然后,我将该映射缓存在Asp.Net Application对象中。
以下是我刚才描述的代码。
代码可以进行优化,以便不是通过所有的错误而只是逐步修改缓存的地图,但即使没有优化,它也能正常工作。
当有人使用标记进行搜索时,我在地图中查找值,获取id列表,然后使用SQL获取这些错误,其中“id in(1,2,3 ...)”条款。
public static void threadproc_tags(object obj)
{
System.Web.HttpApplicationState app = (System.Web.HttpApplicationState)obj;
SortedDictionary<string,List<int>> tags = new SortedDictionary<string,List<int>>();
// update the cache
DbUtil dbutil = new DbUtil();
DataSet ds = dbutil.get_dataset("select bg_id, bg_tags from bugs where isnull(bg_tags,'') <> ''");
foreach (DataRow dr in ds.Tables[0].Rows)
{
string[] labels = btnet.Util.split_string_using_commas((string) dr[1]);
// for each tag label, build a list of bugids that have that label
for (int i = 0; i < labels.Length; i++)
{
string label = normalize_tag(labels[i]);
if (label != "")
{
if (!tags.ContainsKey(label))
{
tags[label] = new List<int>();
}
tags[label].Add((int)dr[0]);
}
}
}
app["tags"] = tags;
}
答案 6 :(得分:0)
关于如何处理标签的快速说明:
标记系统可以从非常严格定义的标记变化,其中创建新标记需要明确的额外工作(想想gmail)到非常松散的系统,其中鼓励添加尽可能多的标记(想想flickr,或标记音频内容,其中转录可能是直接应用为标签)。
通常,易于索引的媒体(文本!)应该具有更严格的系统,因为内容本身 标签 - 其他标签仅存在于分类中。一个更难以索引的媒体(图像,视频)应该有一个灵活的系统,鼓励许多标签,因为它们是你搜索时唯一的希望。
这很重要,因为您想要的数据库架构可能会有所改变,具体取决于您自己找到的频谱的哪一端。