solr入门之solr的拼写检查功能的应用级别尝试

今天主要是收集了些拼写检查方面的资料和 尝试使用一下拼写检查的功能--=遇到了不少问题

拼写检查的四种配置眼下我仅仅算是成功了半个吧


---------------------------------

拼写检查功能,能在搜索时,提供一个较好用户体验。所以,主流的搜索引擎都有这个功能。在这之前,笔者先简单的说一下什么是拼写检查,事实上非常好理解。就是你输入的搜索词,可能是你输错了,也有可能在它的检索库里面根本不存在这个词。可是这时候它能给你返回,相似或相近的结果来帮助你校正。



举个样例。假如你在百度里面输入在在线电瓶,可能它的索引库里面就没有,可是它有可能返回在线电影,在线电视,在线观看等等一些词。这些。就用到拼写检查的功能了。

solr作为一种开源的搜索server,对拼写检查,也提供了良好的支持,那么以下笔者就来讲下关于solr4.3的拼写检查的配置,在这之前先说明一点。作为拼写检查用,为了提高校正的准确率,一般对校正的词,不要进行分词,所以用string就好了,拼写检查的配置主要是在solrconfig.xml里面配置.



1,拼写组件SpellCheckComponent配置
2,在SearchHandler   /select里面配置
3,在SearchHandler   /spell里面配置

依照上面3来,就能够高速配置好拼写检查功能了。事实上笔者上面写的4步。事实上仅仅配置2,3步就能够了。另外的第4步用默认值就能够了。在这里把它写出来。仅仅是让大家有个认识


拼写组件SpellCheckComponent它事实上是核心的东西。在他的里面能够配置1至多个拼写检查器,启动的时候全部的检查器都会载入。这次笔者主要介绍的有2个拼写检查器,一个是默认的仅仅对主索引做拼写校正,另外一个是自己定义载入spellings.txt拼写检查库。带拼写校正索引库的检查器,其它的检查器各位道友想要使用的话就自己去看wiki了。

https://cwiki.apache.org/confluence/display/solr/Spell+Checking


1.配置solrconfig.xml文件的拼写检查的几种方式

   <!--拼写检查设置 -->
      <searchComponent name="spellcheck" class="solr.SpellCheckComponent">  

    <!-- 查询分析器。假设不指定的话,默认会使用field字段类型的分词器  -->  
     <str name="queryAnalyzerFieldType">text_spell</str> 
     <lst name="spellchecker"> 
       <str name="name">direct</str> 
       <str name="field">suggest</str> 
       <str name="classname">solr.DirectSolrSpellChecker</str> 
       <str name="distanceMeasure">internal</str> 
       <float name="accuracy">0.5</float> 
       <int name="maxEdits">2</int> 
       <int name="minPrefix">1</int> 
       <int name="maxInspections">5</int> 
       <int name="minQueryLength">2</int> 
       <float name="maxQueryFrequency">0.01</float> 
    </lst> 
     <!--  读取拼写检查库的索引进行校正能够。使用默认配置,取消凝视就可以 -->  
        <lst name="spellchecker">  
            <str name="classname">solr.FileBasedSpellChecker</str><!--这个组件是载入配置文件来完毕的,检查源是文件能够起效的字段呢?-->  
            <str name="name">file</str>  
            <str name="sourceLocation">spellings.txt</str>  
            <str name="characterEncoding">UTF-8</str>  
            <str name="spellcheckIndexDir">spellcheckerFile</str>  
          </lst>  
<!-- ======================================================================================-->

<lst name="spellchecker">  

      <!--  

        Optional, it is required when more than one spellchecker is configured.  

        Select non-default name with spellcheck.dictionary in request handler.  

        ame是可选的,假设仅仅有一个spellchecker能够不写name  

        果有多个spellchecker,须要在Request Handler中指定spellcheck.dictionary  

      -->  

      <str name="name">base</str>  

      <!-- The classname is optional, defaults to IndexBasedSpellChecker -->  

      <str name="classname">solr.IndexBasedSpellChecker</str>  

      <!--  

               Load tokens from the following field for spell checking,  

               analyzer for the field's type as defined in schema.xml are used  

                以下这个field名字指的是拼写检查的根据,也就是说要根据哪个Field来检查用户输入。  

      -->  

      <str name="field">suggest</str>  

            <!-- Optional, by default use in-memory index (RAMDirectory)   

        SpellCheck索引文件的存放位置,是可选的,假设不写默认使用内存模式RAMDirectory。  

        ./spellchecker1指的是:corex\data\spellchecker1  

        -->  

      <str name="spellcheckIndexDir">./spellchecker-base</str>  

      <!-- Set the accuracy (float) to be used for the suggestions. Default is 0.5 -->  

      <str name="accuracy">0.7</str>  

<!--何时创建拼写索引:buildOnCommit/buildOnOptimize -->  

   <str name="buildOnCommit">true</str>  

    </lst>  

<!-- 还有一个拼写检查器,使用JaroWinklerDistance距离算法  类 那个主索引的方式应该也是能建立的吧 -->  

    <lst name="spellchecker">  

       <str name="name">jarowinkler</str>  

       <str name="classname">solr.IndexBasedSpellChecker</str>  

       <str name="field">suggest</str>  

       <!-- Use a different Distance Measure -->  

       <str name="distanceMeasure">org.apache.lucene.search.spell.JaroWinklerDistance</str>  

       <str name="spellcheckIndexDir">./spellchecker2</str>  

       <str name="buildOnCommit">true</str>  

     </lst>  


<!-- ======================================================================================-->    
     </searchComponent> 
2.配置solr搜索组件部分---select 和spell部分
 <requestHandler name="/select" class="solr.SearchHandler">
    <!-- default values for query parameters can be specified, these
         will be overridden by parameters in the request
      -->
     <lst name="defaults">
       <str name="echoParams">explicit</str>
       <int name="rows">10</int>
     </lst>
    <!-- 这行代码很重要。假设没有这行,拼写检查。是不起作用的-->  
        <arr name="last-components">  
        <str>spellcheck</str>  
      </arr> 
    </requestHandler>
  <!--spell 查询器 -->
  <requestHandler name="/spell" class="solr.SearchHandler" startup="lazy">  
    <lst name="defaults">  
      <str name="df">suggest</str> <!--默认查询字段--> 
      <str name="spellcheck.dictionary">direct</str>  <!--使用那个组件-->
      <str name="spellcheck">on</str>  
      <str name="spellcheck.extendedResults">true</str>              
      <str name="spellcheck.collate">true</str>  
      <str name="spellcheck.collateExtendedResults">true</str>         
    </lst>  
    <arr name="last-components">  
      <str>spellcheck</str>  
    </arr>  
  </requestHandler>


文件方式说明

对于上面的代码。尽管能够载入多个校正器。可是在拼写检查时,仅仅能指定特定的一个进行校正。那么为什么要配置多个校正检查器呢? 笔者个人感觉这个主要是方便在程序执行能够动态切换校正器。



在spellings.txt里面自己定义的拼写检查词,注意编码的格式一定是要UTF-8无BOM的格式。这里面的词。会在solr服务启动时,自己主动创建spellcheckerFile目录并把内容载入到

本库的data文件夹下

3.solr主界面查询尝试


这是是使用direct方式 来进行尝试的 详细的效果 预计和配置的參数 有非常大的关系


关于其余几种方式--我主要在尝试文件夹的方式的载入今天没有搞定呀

明天的尝试下:

以下是一些原理方面的资料;

一、纠错功能。英文叫做spellcheck。在英文上做纠错比較直接。就是看单词的编辑距离,目标当然就是对于随意一个输入,能在大量正确而靠谱的查询词中找出编辑距离满足要求的一个或者几个。

面对这种spellcheck任务,模型上就是要推算用户输入错误单词w的条件下,是正确单词c的概率。也就是argmaxc P(c|w)。

一般有两种方案:一种。是http://norvig.com/spell-correct.html 介绍的办法,还有一种是lucene-suggest里spellchecker的方法。

 


      1. 第一种,在norvig介绍的方法中,具体的阐述了argmaxc P(c|w)的转换和求解办法。 这个概率不好直接算,但能够依据贝叶斯定理等价于argmaxc P(w|c)*P(c) / P(w)。由于是比較各个c之间的大小所以P(w)能够省略,最后就变成求argmaxc P(w|c)*P(c)即可了。P(c)能够看作是c在文本集合中出现的可能性;P(w|c)意味着本来心里想成是c结果打成了w的概率。

那就非常好办了,P(c)能够从靠谱的语料中统计。P(w|c)能够用编辑距离来模拟关系,即编辑距离小的概率大。在实现上,对一个输入word,产生出有编辑距离1的字符串,就包含几种情况:删除一个字符、交换临近字符、把一个字符改成还有一个、添加一个字符。这样产生的候选集会比較大,接近80%的纠错要求是满足了。

假设在编辑距离1的基础上再产生编辑距离为2的更大的候选集。差点儿就覆盖全部错别字了。原文讲得比較精细。建模思路也非常清晰。建议细致阅读,这就不细说了。

      2.另外一种方案就是lucene的spellchecker方法。上面方案是把编辑距离的暂时产生到词典中检查。这样的方案就是预先进行词典索引。当然是ngram的,对一个word随意2位或者3位字符进行索引,对用户输入的一个字符。也同理按2或3位产生字符片段,利用OR的关系去检索。命中多的word得分更高最可能是拼写错误的。当然由于是OR查询关系,所以会有非常多也仅仅“沾边”的词也被命中。所以最后除了考虑查询命中高分的。还要对命中的和输入的进行一步编辑距离阈值过滤。举个样例“word”。我们会有n2:wo/n2:or/n2:rd/n3:wor/n3:ord 这些碎片进行索引,当用户输入一个worg,会产生n2:wo/n2:or/n2:rg/n3:wor/n3:org,这些检索条件,会查到非常多work, worth等等。

细节上能够有一些增强,比方单词两头的字符碎片权重更大等等。

这两种求解argmax P(c|w)的办法,norvig的办法比lucene-spellcheck的办法在线上的环节多一些,效率上预计还是差一点,但提供了非常巧妙的求解思路,值得细细品味。


二、相关搜索的功能,学术界研究的比較多。有各种提法,query rewrite,query substitution, query extension等等。算法也五花八门,大多为了结果好看添加了复杂的计算,和针对数据情况的考量。

一般project上须要的是通用的办法,再添加一些特殊的考虑来提高效果。过去以前有幸看到一篇貌似不是非常正规的论文。方法非常easy,思路清晰,非常适合在实际project上应用起来。论文也不记得标题了。只是思想还记得非常清晰:就是寻找query词之间的强弱联系。

普通情况下构成query之间的关联有三种基本的因素:

     1. 字面意思的关联。假设一个query比还有一个query 多了或者少了一个词。那么这两个词肯定是有关联的。长短语是短短语的详细化,反之是泛化。比方“笔记本 内存条 8G”就是“笔记本 内存条”的细化,反过来看“笔记本 内存条”不仅包含“8G”也包含其它容量,是更泛化的查询词。

     2. 用户输入行为的关联;用户在一个会话之中连续输入的多个词之间能够觉得是有关联的,即做一个人的需求反应在查询词上。比方用户查询了“键盘”他可能还有须要去买点别的,比如“鼠标”之类的。假设这种情况出现了多次,那么“键盘”和“鼠标”就能够看成是有强联系的。

     3. 用户点击行为的关联。用户为了找一个东西的时候可能词不正确重复更换查询词,或者不同人用不同的表达,假设都点到一个结果。能够看做用了不同的办法找到相同的东西,殊途同归的味道。那么这些落到同一结果的路径。即query。也能够看做是有强关联的。


这三种是比較通用的关联关系,也非常直接,而且数据能非常easy获得或者被日志记录下来的。除了这几种,还能够依据详细业务情况添加其它关联考虑。最后。我们能够依据经验或者统计分析调整多种关联关系的权重。实现上,对一个query。须要让查那些和它有关联的queries,都能被找出来。于是想到能够用检索系统,传统的检索系统是对文档的内容直接分词出一个个token后建索引,这里是对query,进行特殊“分词”出那些关联的token去建索引。


      最后,假设要把纠错和相关搜索结合在一起,就有非常多综合考虑了。总之相关搜索是检索之外比較影响用户体验的一个服务。值得投入精力把它做好。

转载:http://blog.csdn.net/lgnlgn/article/details/8760785








posted on 2017-07-10 13:40  blfbuaa  阅读(250)  评论(0编辑  收藏  举报