如何优化MySQL布尔全文搜索? (或者用什么来替换它?) – C#

我有一个包含大约22000行的表,我使用布尔全文搜索来找到我感兴趣的内容。我的问题是我创建了一个’动态搜索感觉’,它包含一个DataGridView ,它被刷新在每次TextChanged事件之后。 正如您可能已经想到的那样,在每个事件之后搜索插入的字符串需要花费大量时间。

我该怎么做才能提高搜索速度?

欢迎任何建议!

首先,您应该意识到RDBMS对全文索引的支持是一种强制技术,旨在允许有效访问结构化数据以处理非结构化文本。 (是的,这只是我的意见。如果需要,我可以保护它,因为我非常了解这两种技术。;)

那么,可以做些什么来提高搜索性能呢?

方案一 – “任务的最佳工具”

在文档语料库中处理全文搜索的最佳方法是专门设计的使用技术,例如来自Apache的SOLR (Lucene)或来自err,Sphinx的Sphinx。

由于下面将要明确的原因,我强烈推荐这种方法。

选项二 – 预加载结果

在构建基于文本的搜索解决方案时,通常的方法是将所有文档索引到单个可搜索索引中,虽然这可能是最方便的,但这不是唯一的方法。

假设您正在搜索的内容可以轻松量化为一组已知规则,您可以提供更多“引导”搜索风格,而不仅仅是不合格的全文。 我的意思是,如果您的应用程序可能会受益于将用户指向结果,您可以根据已知的一组规则将各种结果集预加载到他们自己的表中,从而减少要搜索的大量数据。

如果您希望大多数用户能够以已知顺序从一组已知搜索字词中受益,则可以构建搜索UI以支持这些字词。

因此,假设大多数用户正在寻找各种汽车,您可以根据型号,年份,条件等提供预定义搜索。您的搜索UI将被制作为一系列下拉菜单,以“引导”用户获得特定结果。

或者,如果大多数搜索都是针对特定的主题(比如“汽车”),那么您可以预定义一张仅包含您之前已确定与汽车相关的记录的表格。

这两种方法都会减少要搜索的记录数量,从而增加响应时间。

方案三 – “自己动手”

如果您无法将外部搜索技术集成到项目中并且预加载不是一种选择,那么仍然有很多方法可以大大改善搜索查询响应时间,但它们会根据您需要完成的工作以及您希望如何执行搜索而有所不同。

如果您希望用户使用单个关键字或短语以及它们之间的布尔关系进行搜索,您可以考虑构建自己的语料库“ 倒排索引 ”。 (这就是MySQL的布尔全文搜索已经做到的,但是自己动手做可以更好地控制搜索的速度和准确性。)

要从现有数据构建反向索引:

步骤1.创建三个表

     // dict  - 语料库中每个唯一单词包含一行的字典  
    创建表dict(    
       id int主键,  
       word varchar  
     )

     // invert  - 使用inverted_index将单词映射到语料库中的记录  
    创建表反转(    
       id int主键,  
       rec_id int,  
       word_id int  
     )

     // stopwords  - 包含索引时要忽略的单词(如a,an,the等)
    创建表停用词( 
       id int主键,  
       word varchar  
     )

注意:这只是一个草图。 实际创建这些表时,您将需要添加索引和约束等。

停用词表用于将索引的大小减少到仅对用户的预期查询重要的单词。 例如,对英语文章进行索引很少有用,例如’a’,’an’,’the’,因为它们对关键字搜索没有贡献有用的意义。

通常,您需要一个专门针对您的应用程序需求制作的禁用词列表。 如果您从不希望用户在其查询中包含术语“红色”,“白色”或“蓝色”,或者这些术语出现在每个可搜索记录中,您可能希望将它们添加到您的禁用词列表中。

有关在MySQL中使用自己的停用词列表的说明,请参阅此消息末尾的注释。

也可以看看:

  • MySQL中支持的当前停用词列表

  • 一个很好的英语起始词

第2步。构建倒置索引

要从现有记录构建反向索引,您需要(伪代码):

     foreach(记录中的单词(w)(r)){
       if(w不是停用词){
         if(w在字典中不存在){
          在w.id上插入w到字典
         }
        将(r.id,w.id)插入inverted_index
       }
     }

更多关于停用词:

而不是使用特定的禁用词列表,’if(w不是停用词)’测试可以做出其他决定,而不是作为不可接受的单词列表的附件。

您的应用程序可能希望过滤掉长度小于4个字符的所有单词,或仅包含预定义集合中的单词。

通过创建自己的倒排索引,您可以获得更大,更细粒度的搜索控制。

步骤3.使用SQL查询反向索引

此步骤实际上取决于您希望查询提交到索引的方式。

如果查询是“硬编码”的,您可以自己创建select语句,或者如果需要支持用户输入的查询,则需要将您选择的任何查询语言转换为SQL语句(通常使用简单的解析器)。

假设您希望检索与逻辑查询’(word1 AND word2)或word3’匹配的所有文档,可能的方法可能是:

 CREATE TEMPORARY TABLE temp_results ( rec_id int, count int ) AS ( SELECT rec_id, COUNT(rec_id) AS count FROM invert AS I, dict AS D WHERE I.word_id=D.id AND (D.word='word1' OR D.word='word2') GROUP BY I.rec_id HAVING count=2 ) UNION ( SELECT rec_id, 1 AS count FROM invert AS I, dict AS D WHERE I.word_id=D.id AND D.word='word3' ); SELECT DISTINCT rec_id FROM temp_results; DROP TABLE temp_results; 

注意:这只是我头顶的第一次传球。 我相信有更有效的方法可以将布尔查询表达式转换为高效的SQL语句,并欢迎任何改进建议。

要搜索短语,您需要在倒排索引中添加一个字段,以表示该单词在其记录中出现的位置,并将其计入SELECT中。

最后,当您添加新记录或删除旧记录时,您需要更新反向索引。

最后一句话

“全文检索”属于一个非常大的研究领域,称为“信息检索”或IR,有很多关于这一主题的书籍,包括

  • 信息检索:实施和评估搜索引擎 StefanBüttcher,Charles LA Clarke和Gordon V. Cormack(2010年7月23日)

  • 搜索引擎: Bruce Croft,Donald Metzler和Trevor Strohman的实践中的信息检索 (2009年2月16日)

  • 构建搜索应用程序:Lucene,LingPipe和 Manu Konchady的门 (2008年6月)

查看亚马逊的更多信息

笔记

如何在MySQL中使用自己的停用词列表

要在MySQL中使用您自己的禁用词列表:

  1. 创建自己的停用词列表,每行一个单词,并将其保存到服务器上的已知位置,例如:/usr/local/lib/IR/stopwords.txt
  2. 编辑my.cnf以添加或更新以下行:
        的[mysqld]  
        的ft_min_word_len = 1    
         ft_max_word_len = 40  
         ft_stopword_file =的/ usr / local / lib目录/ IR / stopWords.txt中
    

    它将合法单词的最小和最大长度分别设置为1和40,并告诉mysqld在哪里可以找到自定义的停用词列表。

    (注意:默认的ft_max_word_len是84,我认为这是非常过分的,并且可能导致非真实单词的字符串运行被索引。)

  3. 重启mysqld
  4. 删除并重新创建所有与全文相关的索引