用于标记,云和搜索的最佳数据架构(如StackOverflow)?

时间:2008-10-24 18:38:33

标签: database-design tags full-text-search tag-cloud

我很想知道Stack Overflow的标记和搜索是如何构建的,因为它看起来效果很好。

如果我想要执行以下所有操作,那么什么是良好的数据库/搜索模型:

  1. 在各种实体上存储标签,(如何规范化?即实体,标签和Entity_Tag表?)
    • 搜索带有特定标签的项目
    • 构建适用于特定搜索结果集
    • 的所有代码的代码云
    • 如何在搜索结果中显示每个项目的标记列表?
  2. 将标签存储在标准化形式中也许是有意义的,但也可以作为空格分隔的字符串用于#2,#4和#3的目的。想法?

    我听说它说Stack Overflow使用Lucene进行搜索。真的吗?我听过几个关于SQL优化的播客,但没有关于Lucene的内容。如果他们确实使用Lucene,我想知道有多少搜索结果来自Lucene,以及“钻取”标签云是否来自Lucene。

2 个答案:

答案 0 :(得分:57)

哇我刚写了一个很棒的帖子,所以窒息并挂在上面,当我按下我的后退按钮重新提交时,标记编辑器是空的。 aaargh。

所以我再来一次......

关于Stack Overflow,事实证明他们使用SQL server 2005 full text search

关于@Grant推荐的操作系统项目:

  • * DotNetKicks 使用数据库进行标记,使用Lucene进行全文搜索。似乎无法将全文搜索与标记搜索结合起来
  • Kigg 使用Linq-to-SQL进行搜索和标记查询。这两个查询都会加入Stories-> StoryTags->标记。
  • 两个项目都有一个3表格的标记方法,因为每个人似乎都建议

我还发现了其他一些我之前错过的问题:

我目前正在为我提到的每件事做些什么:

  1. 在DB中,有3个表:Entity,Tag,Entity_Tag。我使用DB来:
    • 构建站点范围的标记云
    • 按标签浏览(例如SO的 /questions/tagged/ASP.NET 等网址)
  2. 对于搜索,我使用Lucene + NHibernate.Search
    • 标签被连接到由Lucene索引的TagString中
      • 所以我拥有Lucene查询引擎的全部功能(AND / OR / NOT查询)
      • 我可以同时搜索文字按标签过滤
      • Lucene分析器合并单词以获得更好的标签搜索(即标签搜索“test”也会找到标记为“testing”的内容)
    • Lucene返回一个潜在的巨大结果集,我将其分为20个结果
    • 然后NHibernate从数据库或实体缓存
    • 加载结果实体ID
    • 因此,搜索结果可能会导致数据库的0次点击
  3. 还没有这样做,但我想我可能会尝试找到一种方法来从Lucene的TagString构建标签云,而不是采取另一个数据库命中
  4. 还没有这样做,但我可能会将TagString存储在数据库中,以便我可以显示实体的标记列表而无需再进行2次连接。
  5. 这意味着每当修改实体的标签时,我都必须:

    • 插入任何尚不存在的新标签
    • 从EntityTag表中插入/删除
    • 更新Entity.TagString
    • 更新实体的Lucene索引

    鉴于在我的应用程序中读取与写入的比例非常大,我想我对此很满意。唯一真正耗时的部分是Lucene索引,因为Lucene只能从其索引插入删除,所以我必须重新索引整个实体才能更新TagString。我对此并不感到兴奋,但我认为如果我在后台线程中这样做,那就没问题了。

    时间会告诉......

答案 1 :(得分:5)

我不知道它们是否符合最佳条件,但DotNetKicks和Kigg都是开源的digg克隆实现。你可以看看他们是如何做标签和搜索的。

我最好的猜测,没有经过深思熟虑:)。

  1. 我从不喜欢将多个值序列化到单个字段中的想法,因此存储在一个字段中的分隔字符串对我不具吸引力......可能适用于带树的邻接路径,但这些字符串总是有序且标签不需要是。这似乎会对LIKE运营商的工作征税,以便找到它们。
  2. 所以我最初的看法可能是实体 - > EntityTag< - Tag。

    1. 这种方法可以很方便地通过Tag查找项目,通过EntityTag加入,一天调用它。

    2. 您需要在此处进行二次操作才能为结果集选择不同的标记。所以a。)拉结果集,b。)标准化标签空间。我认为无论答案是什么,你都会这样做 - 即使将标签填充到一个字段中仍然会产生重复的标签(并且你必须反序列化它们才能执行这个操作 - 所以更多的工作,完全关系的另一个论点方法)。

    3. 还很容易。这是序列化方法更好地工作的一个领域。无需加入子标签,它就在实体中。也就是说,通过两个表连接拉出0..n标签对我来说似乎并不太具有挑战性。如果您正在讨论性能考虑因素,请首先将其标准化,然后通过缓存或变性进行优化。

    4. 另一种选择是“同时做”。这感觉就像是一个过早的优化,但您可以执行完全规范化的方法来支持任何以标记为中心的操作,并在持久化时序列化以在实体中具有非规范化版本。更多的工作,如果没有完全覆盖,有些可能会失去同步,但如果在用例中完全规范化的方式存在实际限制,那么这两个方面都是最好的。

      Lucene也很有趣,您可以在索引IIRC中声明特定元数据,因此您也可以通过这种方式利用标记搜索。我的怀疑是,如果你走这条路太远,那么你最终会在数据库中存储的内容和某个时刻的索引之间断开连接。我可以对Lucene赞不绝口,它非常强大且易于使用 - 我相信.Text使用它的搜索功能,并且在切换到社区服务器之前支持所有的weblogs.asp.net。如果MSSQL不在图片中,我会坚持使用全文搜索/解决数据库imo中的标记问题。