【问题标题】:how an search index works when querying many words?查询多个单词时搜索索引如何工作?
【发布时间】:2012-03-12 08:20:08
【问题描述】:

我正在尝试构建自己的搜索引擎进行实验。

我知道倒排索引。例如在索引单词时。

键是单词,并且有一个包含该单词的文档 ID 列表。因此,当您搜索该单词时,您会立即获得文档

如何处理多个单词

您获取每个单词的所有文档并遍历这些文档以查看是否有两个单词?

我觉得不是这样的。

任何人都知道这个问题的真正答案而不用猜测吗?

【问题讨论】:

  • 如果您可以获取单词 A 的所有文档(或文档 ID)并且可以为单词 B 执行相同的操作,那么您还可以在不打开文档本身的情况下生成两个结果集的交集。

标签: search lucene full-text-search search-engine


【解决方案1】:

使用 zig-zag 算法,倒排索引对于获取交点非常有效:

假设你的条件是一个列表T

lastDoc <- 0 //the first doc in the collection
currTerm <- 0 //the first term in T
while (lastDoc != infinity):
  if (currTerm > T.last): //if we have passed the last term:
     insert lastDoc into result
     currTerm <- 0
     lastDoc <- lastDoc + 1
     continue
  docId <- T[currTerm].getFirstAfter(lastDoc-1)
  if (docID != lastDoc):
     lastDoc <- docID
     currTerm <- 0
  else: 
     currTerm <- currTerm + 1

该算法假定有效的getFirstAfter() 可以为您提供第一个适合该术语的文档,并且他的 docId 大于指定的参数。如果没有,它应该返回无穷大。

如果对术语进行排序以使最稀有的术语在前,则该算法将是最有效的。

该算法最多可确保#docs_matching_first_term * #terms 次迭代,但实际上 - 它通常会少得多的迭代次数。

注意:虽然此算法很有效,但 AFAIK lucene 不使用它。

更多信息可以在this lecture notes slides 11-13 [版权在讲座第一页]

【讨论】:

    【解决方案2】:

    您需要在索引文件的文档中存储单词的位置。 你的索引文件结构应该是这样的.. word id - doc id- 没有。命中数 - 命中数。

    现在假设查询包含 4 个单词 "w1 w2 w3 w4" 。选择那些包含大部分单词的文件。现在计算它们在文档中的相对距离。出现最多单词且相对距离最小的文档将在搜索结果中具有高优先级。

    我开发了一个完整的搜索引擎,没有使用任何互联网上可用的抓取或索引工具。你可以在这里阅读详细说明-Search Engine

    有关更多信息,请阅读 Google 创始人的这篇论文-click here

    【讨论】:

      【解决方案3】:

      您可以像 biziclop 所说的那样找到文档集的交集,并且可以以相当快的方式完成。请参阅this post 和其中链接的论文以获得更正式的描述。

      【讨论】:

      • 这篇文章并没有真正解决匹配列表 intersection(即 AND 查询)的问题,因为它谈到了 OR 查询。
      • @jogojapan:链接的论文是核心实现细节。我认为重要的部分是可以通过仅找到前 k 个来改进边界。
      【解决方案4】:

      正如 biziclop 所指出的,对于 AND 查询,您需要将两个查询词的匹配列表(也称为倒排列表)相交。

      在典型的实现中,倒排列表的实现使得它们可以非常有效地搜索任何给定的文档 id(通常在对数时间内)。实现这一点的一种方法是保持它们排序(并使用二分搜索),但请注意,这并非易事,因为还需要以压缩形式存储它们.

      给定一个查询A AND B,并假设 A 有 occ(A) 匹配,B 有 occ(B) 匹配(即 occ(x) := 术语 x 的匹配列表的长度)。假设不失一般性,occ(A) > occ(B),即 A 在文档中比 B 更频繁地出现。然后您要做的是遍历 B 的所有匹配项并在列表中搜索它们中的每一个对于 A。如果确实可以在对数时间内搜索列表,这意味着您需要

      occ(B) * log(occ(A))
      

      识别包含这两个术语的所有匹配项的计算步骤。

      描述实现各个方面的好书是Managing Gigabytes

      【讨论】:

        【解决方案5】:

        我真的不明白为什么人们为此谈论交集。

        Lucene 支持使用 BooleanQuery 组合查询,如果必须,可以无限嵌套。

        QueryParser 还支持 AND 关键字,这需要两个词都在文档中。

        示例(Lucene.NET、C#):

        var outerQuery + new BooleanQuery();
        outerQuery.Add(new TermQuery( new Term( "FieldNameToSearch", word1 ) ), BooleanClause.Occur.MUST );
        outerQuery.Add(new TermQuery( new Term( "FieldNameToSearch", word2 ) ), BooleanClause.Occur.MUST );
        

        如果您想使用相同的分析器拆分单词(您的实际搜索词),也有一些方法可以做到这一点。虽然,QueryParser 可能更容易使用。

        您可以查看此答案,例如,如何使用与索引相同的分析器拆分字符串:

        No hits when searching for "mvc2" with lucene.net

        【讨论】:

        • 你的 "a" AND "b" 查询精确计算匹配 "a" 的文档集和匹配 "b" 的文档集之间的交集
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-02
        • 2020-12-29
        • 2018-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多