对于Solr应该不须要过多介绍了,强大的功能也是都体验过了,可是solr一个较大的问题就是分词问题,特别是中英文的混合分词,处理起来很是棘手。 虽然solr自带了支持中文分词的cjk,可是其效果实在很差,因此solr要解决的一个问题就是中文分词问题,这里推荐的方案是利用ik进行分词。java
ik是较早做中文分词的工具,其效果也是获得多数用户认同。可是如今做者彷佛更新缓慢,对于最新的solr4.4支持很差,最新的更新也停留在2012年。apache
虽然不支持4.4版本(这也不是做者的错,solr的lucene的新版本接口都进行了修改,除非修改实现否则就无法向下兼容),可是咱们也有办法的,咱们能够利用他的分词工具本身封装一个TokenizerFactory,经过实现最新的4.4接口就可让solr4.4用上ik了。ide
首先就是就在下载ik的原码,最新版是 而后本身实现一个TokenizerFactory:工具
package org.wltea.analyzer.lucene; import java.io.Reader; import java.util.Map; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.util.TokenizerFactory; import org.apache.lucene.util.AttributeSource.AttributeFactory; public class IKAnalyzerTokenizerFactory extends TokenizerFactory{ private boolean useSmart; public boolean useSmart() { return useSmart; } public void setUseSmart(boolean useSmart) { this.useSmart = useSmart; } public IKAnalyzerTokenizerFactory(Map<String, String> args) { super(args); assureMatchVersion(); this.setUseSmart(args.get("useSmart").toString().equals("true")); } @Override public Tokenizer create(AttributeFactory factory, Reader input) { Tokenizer _IKTokenizer = new IKTokenizer(input , this.useSmart); return _IKTokenizer; } }
而后从新打包jar放到solr的执行lib里,同时新建一个fieldType测试
<fieldType name="text_ik" class="solr.TextField" > <analyzer type="index"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="false"/> </analyzer> <analyzer type="query"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="true"/> </analyzer> </fieldType>
测试一下咱们新的分词器:ui
// 输入
移动互联网
// 输出
移动,互联网,互联,联网
从结果来看,其效果仍是比较不错的。this
搞定了中文咱们须要搞定英文 英文简单的分词是按照空格,标点,stopword等来分词。 好比I'm coding
通常能够分词为I'm, coding
或者I, m, coding
。通常状况下这样也是能够接受的,可是若是用户输入code
,是否应该搜到结果呢,若是要搜到该结果,那么咱们须要处理咱们的英文分词。google
这里提供一种简单的实现,就是采用NGramFilterFactory,该过滤器简单的按照长度对词进行切分,该过滤器有两个参数minGramSize
和maxGramSize
,分别表示最小和最大的切分长度,默认是1
和2
。spa
<analyzer> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="4"/> </analyzer>
好比设置(min,max)为(3,5),咱们上面的句子“I'm coding”会获得如下的结果:code
I'm,cod,codi,codin,coding,odi,odin,oding,din,ding,ing
固然这里也会有问题,就是小于3个词长的都会被过滤调,特别是中文和英文采用的是同一词长处理,若是min设为3,那么像我,咱们
这样的都会被过滤,解决办法就是min设为1,这样的结果就是会大大增长索引记录。影响检索速度。好处就是能够实现字母级别的匹配,而后经过设置匹配度阔值提高了搜索质量。
分别处理完了中文和英文,那么就要混合中英文处理了
方案一是使用StandardTokenizerFactory和NGramFilterFactory,加上辅助的StopFilterFactory和LowerCaseFilterFactory等过滤器处理。也就是中文默认是按字逐个分开,固然前提是NGramFilterFactory的minGramSize
要设置为1。
方案二则是IKAnalyzerTokenizerFactory和NGramFilterFactory,经过ik实现对词的索引,而后在经过ngram进行长度分割。即在方案一的基础上增长对词的索引,提高索引质量。
方案一和方案二若是还不够和谐的,那么咱们还有个办法就是自定义的反感三,所谓自定义,本身写个tokenizer或者filter不就能够了,并且这一点也不复杂,这里就不细说了,有机会再专门写一个。
最后来个整合的配置参考一下:
<fieldType name="text_ik" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="false"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="20"/> </analyzer> <analyzer type="query"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="true"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="10"/> </analyzer> </fieldType>
这里所提出的并非最优的方案,或者说多是比较傻瓜化的方案,可是solr的优点就是自由,你能够本身组合各类tokenizer和filter来实现你要的效果,或者干脆本身去实现tokenizer和filter,而后让强大的solr服务于你的项目。
参考: