标签:
今天主要是收集了些拼写检查方面的资料和 尝试使用一下拼写检查的功能--=遇到了不少问题
拼写检查的四种配置目前我只算是成功了半个吧
---------------------------------
拼写检查功能,能在搜索时,提供一个较好用户体验,所以,主流的搜索引擎都有这个功能。在这之前,笔者先简单的说一下什么是拼写检查,其实很好理解,就是你输入的搜索词,可能是你输错了,也有可能在它的检索库里面根本不存在这个词,但是这时候它能给你返回,相似或相近的结果来帮助你校正。
举个例子,假如你在百度里面输入在在线电瓶,可能它的索引库里面就没有,但是它有可能返回在线电影,在线电视,在线观看等等一些词,这些,就用到拼写检查的功能了。
solr作为一种开源的搜索服务器,对拼写检查,也提供了良好的支持,那么下面笔者就来讲下关于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等等,算法也五花八门,大多为了结果好看加入了复杂的计算,和针对数据情况的考量。一般工程上需要的是通用的办法,再增加一些特殊的考虑来提高效果。过去曾经有幸看到一篇貌似不是很正规的论文,方法非常简单,思路清晰,非常适合在实际工程上应用起来。论文也不记得标题了,不过思想还记得很清楚:就是寻找query词之间的强弱联系。
一般情况下构成query之间的关联有三种主要的因素:
1. 字面意思的关联;如果一个query比另一个query 多了或者少了一个词,那么这两个词肯定是有关联的,长短语是短短语的具体化,反之是泛化,比如“笔记本 内存条 8G”就是“笔记本 内存条”的细化,反过来看“笔记本 内存条”不仅包括“8G”也包括其他容量,是更泛化的查询词。
2. 用户输入行为的关联;用户在一个会话之中连续输入的多个词之间可以认为是有关联的,即做一个人的需求反应在查询词上。比如用户查询了“键盘”他可能还有需要去买点别的,例如“鼠标”之类的,如果这样的情况出现了多次,那么“键盘”和“鼠标”就可以看成是有强联系的。
3. 用户点击行为的关联;用户为了找一个东西的时候可能词不对反复更换查询词,或者不同人用不同的表达,如果都点到一个结果,可以看做用了不同的办法找到同样的东西,殊途同归的味道。那么这些落到同一结果的路径,即query,也可以看做是有强关联的。
这三种是比较通用的关联关系,也很直接,并且数据能很容易获得或者被日志记录下来的。除了这几种,还可以根据具体业务情况增加其他关联考虑。最后,我们可以根据经验或者统计分析调整多种关联关系的权重。实现上,对一个query,需要让查那些和它有关联的queries,都能被找出来。于是想到可以用检索系统,传统的检索系统是对文档的内容直接分词出一个个token后建索引,这里是对query,进行特殊“分词”出那些关联的token去建索引。
最后,如果要把纠错和相关搜索结合在一起,就有很多综合考虑了。总之相关搜索是检索之外比较影响用户体验的一个服务,值得投入精力把它做好。
转载:http://blog.csdn.net/lgnlgn/article/details/8760785
标签:
原文地址:http://blog.csdn.net/sqh201030412/article/details/51029591