代码之家  ›  专栏  ›  技术社区  ›  slashmais

动态搜索和显示

  •  0
  • slashmais  · 技术社区  · 16 年前

    我有大量的文档,文本文件,我想搜索相关的内容。我看到了一个搜索工具,无法记起在哪里实现了一个很好的方法,正如我在下面的需求中描述的那样。

    我的要求如下:

    • 我需要一个优化的搜索功能:我为这个搜索功能提供一个列表(一个或多个)部分完成(或完整)的单词,用空格隔开。
    • 然后,函数查找所有包含以第一个单词开头或等于第一个单词的单词的文档,然后使用第二个单词以相同的方式搜索这些找到的文档,依此类推,在文档末尾返回一个包含找到的实际单词的列表,该列表与包含这些单词的文档(名称和位置)链接,以完成工作列表。DS。
    • 文件必须包含 全部的 列表中的单词。
    • 我想用这个函数来做一个随你输入的搜索,这样我就可以实时显示和更新树形结构中的结果。

    我提出的解决方案可能的方法如下: 我创建了一个数据库(很可能使用MySQL),其中有三个表:“documents”、“words”和“word_docs”。

    • “文档”将包含所有文档的(iddoc、名称、位置)。
    • “words”将具有(idword,word),并且是所有文档中的唯一单词列表(特定单词只出现一次)。
    • “word_docs”将具有(id word,iddoc),并且是每个单词及其显示的文档的唯一ID组合列表。

    然后在每次按键时使用编辑框的内容调用函数(空格除外):

    • 字符串被标记化
    • (这里我的轮子旋转了一下):我确信可以构造一个SQL语句来返回所需的数据集:(实际的单词,文档名,文档位置);(我不是SQL的热号),或者是对每个令牌的一系列调用并解析出不重复的iddocs?
    • 然后返回此数据集(/list/array)

    然后显示返回的列表内容:

    例如:用“seq sta cod”调用 显示器:

    sequence - start - code - Counting Sequences [file://docs/sample/con_seq.txt]
             - stop - code - Counting Sequences [file://docs/sample/con_seq.txt]
    sequential - statement - code - SQL intro [file://somewhere/sql_intro.doc]
    

    (等等)

    这是一种最佳的方法吗?该函数需要很快,还是应该只在命中空格时调用它? 它应该提供单词补全吗?(在数据库中得到单词)至少这可以防止对不存在单词的函数进行无用的调用。 如果单词完成:该如何实现?

    (也许也可以使用这种类型的搜索解决方案浏览标签?(位于主页右上角)

    4 回复  |  直到 16 年前
        1
  •  2
  •   Nick Johnson    16 年前

    你所说的被称为 inverted index 或者张贴清单,并且操作类似于你的提议和麦基的提议。有很多关于倒排索引的文献;维基百科的文章是一个很好的开始。

    更好的方法是使用现有的反向索引实现,而不是自己构建它。MySQL和PostgreSQL的最新版本默认都有全文索引。您也可以退房 Lucene 一个独立的解决方案。写一篇文章要考虑很多事情 好的 反向索引,包括标记化、词干化、多字查询等,预构建的解决方案将为您完成所有这些工作。

        2
  •  1
  •   Mecki    16 年前

    最快的方法当然是根本不使用数据库,因为如果使用优化的数据手动进行搜索,您可以轻松击败select搜索性能。假设文档不经常更改,最快的方法是建立索引文件并使用这些文件查找关键字。索引文件的创建方式如下:

    1. 在文本文件中查找所有唯一的单词。它将文本文件按空格拆分为单词,并将每个单词添加到列表中,除非已在该列表中找到。

    2. 把你找到的所有单词按字母顺序排列;最快的方法是使用 Three Way Radix QuickSort . 在对字符串进行排序时,该算法的性能很难击败。

    3. 将排序后的列表写入磁盘,一行一个字。

    4. 当您现在想搜索文档文件时,完全忽略它,而是将索引文件加载到内存中,并使用二进制搜索来确定索引文件中是否有单词。在搜索大型排序列表时,二进制搜索很难击败。

    或者,可以在单个步骤中合并步骤(1)和步骤(2)。如果您使用insertionsort(它使用二进制搜索来找到正确的插入位置,将一个新元素插入到一个已经排序的列表中),那么您不仅有一个快速的算法来确定这个词是否已经在列表中,如果它不在列表中,您会立即得到正确的插入位置,如果您总是插入这样的新词,那么,yo当你进入步骤(3)时,你会自动得到一个排序列表。

    问题是,每当文档更改时,都需要更新索引…但是,对于数据库解决方案来说,这不是真的吗?另一方面,数据库解决方案为您带来了一些优势:您可以使用它,即使文档包含如此多的单词,索引文件也无法再放入内存中(不太可能,因为即使是所有英文单词的列表也可以放入任何普通用户PC的内存中);但是,如果您需要加载大量文档的索引文件,则记忆可能会成为一个问题。好吧,你可以使用巧妙的技巧来解决这个问题(例如,使用mmap直接搜索映射到内存中的文件等),但是数据库已经使用了这些技巧来执行快速查找,因此为什么要重新发明轮子呢?此外,还可以防止文档更改时(即,如果数据库可以为您执行锁定,或者可以作为原子操作执行更新)在搜索单词和更新索引之间出现锁定问题。对于使用Ajax调用列表更新的Web解决方案,使用数据库可能是更好的解决方案(如果这是一个用C等低级语言编写的本地运行的应用程序,那么我的第一个解决方案相当合适)。

    如果您想在一个选择调用中完成这一切(这可能不是最佳的,但是当您使用Ajax动态更新Web内容时,它通常被证明是导致最少头痛的解决方案),那么您需要将这三个表连接在一起。可能SQL有点生疏,但我会尝试一下:

    SELECT COUNT(Document.idDoc) AS NumOfHits, Documents.Name AS Name, Documents.Location AS Location 
    FROM Documents INNER JOIN Word_Docs ON Word_Docs.idDoc=Documents.idDoc 
    INNER JOIN Words ON Words.idWord=Words_Docs.idWord
    WHERE Words.Word IN ('Word1', 'Word2', 'Word3', ..., 'WordX')
    GROUP BY Document.idDoc HAVING NumOfHits=X
    

    好吧,也许这不是最快的选择…我想可以做得更快。无论如何,它将找到所有至少包含一个单词的匹配文档,然后按ID将所有相等的文档分组在一起,计算已分组到一起的文档数,最后只显示numofhits(在语句中找到的单词数)等于in语句中单词数的结果(如果搜索10个单词,则X是10)。

        3
  •  0
  •   Sklivvz    16 年前

    不确定语法(这是SQL Server语法),但:

    -- N is the number of elements in the list
    
    SELECT idDoc, COUNT(1)
    FROM Word_Docs wd INNER JOIN Words w on w.idWord = wd.idWord
    WHERE w.Word IN ('word1', ..., 'wordN')
    GROUP BY wd.idDoc
    HAVING COUNT(1) = N
    

    也就是说,不用like。相似的事情要复杂得多。

        4
  •  0
  •   jfs    16 年前

    Google Desktop Search 或者类似的工具可能满足您的需求。

    推荐文章