Solr搜索引擎使用介绍-构建一个简单的搜索服务
最近接触到开源搜索引擎Solr,碰了不少坑,在这里备忘一下,了解有限,仅供个人学习···
关于服务搭建等就不多说了,网上一大堆,这里记录一下一些容易出问题的地方等。
我用的是solr-4.3.1.tgz,貌似现在已经是4.4版本了,下载地址这里有,在使用Solr的时候一定注意版本问题,由于他是基于Lurance的,所以难免不断的跟着Lurance改动代码,也就导致某些模块上下不兼容。
solr有本专门介绍的书:《Solr 1.4 Enterprise Search Server》下面记录一些使用的小方法。
零、如何支持完全匹配排在最前面?
solr默认会根据复杂的评分机制来决定某个结果文档的顺序,所以不可避免有些时候检索文档某个字段完全匹配的结果却排在后面,比如搜索书名的时候,用户搜索“人性的弱点”,结果文档《人性的弱点》 排在《人性的弱点和人性的优点》的后面,这样的情况可能不符合需求。
那如何修改这个排序呢?我们可以增加一个exactmatch_name的字段用来调整排序,这个字段的类型是string,也就solr不会对其进行分词,这样比较的时候就是最字符串简单比较了,如果搜索的关键字跟这个书名完全匹配,那么可以通过增加这个字段的权重来让完全匹配结果排在前面,配置为:
<!--schema.xml 模式配置文件,用来配置搜索的字段的含义,类型,分词方法。-->
然后在solrconfig.xml文件的处理搜索请求的requestHandler里面将2个字段的权重对比加入进去,这里使用dismax的搜索类型,qf字段用来控制不同字段间的排序的,用法看看官方文档的介绍:
List of fields and the "boosts" to associate with each of them when building DisjunctionMaxQueries from the user's query. The format supported is fieldOne^2.3 fieldTwo fieldThree^0.4, which indicates that fieldOne has a boost of 2.3, fieldTwo has the default boost, and fieldThree has a boost of 0.4 ... this indicates that matches in fieldOne are much more significant than matches in fieldTwo, which are more significant than matches in fieldThree.
配置如下:
<!--solrconfig.xml。--> <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> <str name="df">nickname</str> <str name="defType">dismax</str> <str name="qf">exactmatch_name^100.0 name^1.0</str> </lst>
其中qf字段的配置为exactmatch_name^100.0 nickname^1.0,代表如果exactmatch_name字段如果匹配的话(简单字符串匹配,不分词),也就是关键词完全匹配,那么气权重很高为100,正常的话权重为1,这样就能让其排在前面。
一、如果文档数目非常大,索引空间太大速度怎么办?
如果出现文档数目上千万或者上亿,索引空间很大,势必会影响搜索速度,这样可以通过在solr的输出文件out.log中看到:
</pre> 186595898 [46080087@qtp-936146014-2410] INFO org.apache.solr.core.SolrCore - [chenzhenianqing] webapp=/solr path=/select params={sort=vip+desc,+score+desc&start=0&q=原理&json.nl=map&wt=json&rows=50} hits=1522001 status=0 QTime=80 186595969 [46080087@qtp-936146014-2410] INFO org.apache.solr.core.SolrCore - [chenzhenianqing] webapp=/solr path=/select params={sort=vip+desc,+score+desc&start=0&q=低频字tt&json.nl=map&wt=json&rows=50} hits=12 status=0 QTime=0 <pre>
上面 2条搜索关键字,第一条搜索“原理”,结果索引命中数目达到150W条数据,这样solr需要对其进行排序,速度肯定会很慢了。第二条搜索“低频字”,出现的索引命中很少,只有12条,这样速度几乎为0,很快。
那么怎么解决这个问题呢?我们可以牺牲一点点准确度,其实牺牲的几乎可以忽略,从分词下手,让索引没那么多。也就是改进索引的方式,让分词少一点,长一点。solr.ShingleFilterFactory可以解决这个问题。参数minShingleSize正好设置最小的分词数目,默认为2,这样solr索引就不会一个个英文单词,中文字符分词了。配置如下:
<filter class="solr.WordDelimiterFilterFactory" splitOnCaseChange ="0" splitOnNumerics ="1" stemEnglishPossessive ="0" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" preserveOriginal="0" /> ```` 同上面,索引和搜索的时候分词方式一样。
结果可以造solr管理界面看到,分词方式确实发生变化了,两两合并了,这样其实对搜索质量影响很少。
修改完后,需要重建索引,因为分词方式改变了,可能需要点时间重建索引。速度会有明显提高的。我之前从400ms降低到了40ms,一个数量级。
二、如何支持中文分词?
solr是在Luence基础上开发的,其中文分词也大都从后者演化出来。常用的中文分词器可以在这里看到。这里介绍一下比较活跃的IK中文分词器。
其实配置很简单,只是由于版本问题,Lucence4.0改动很多,所以坑人不少。千万别下错版本了。
我下载的是这个版本: IK Analyzer 2012FF_hf1.zip 。对应solr4.3.1,亲测可用。
解压后将其IKAnalyzer2012FF_u1.jar文件放到solr/solr-webapp/webapp/WEB-INF/lib目录下,java就会自动(靠,自动···个人不喜欢这种找全目录.jar的方式)扫描这个目录加载所有的.jar文件。
然后配置很简单,增加一个text_chinese的fieldType,修改原先name字段的类型为text_chinese。
//schema.xml <field name="name" type="text_chinese" indexed="true" stored="true" omitNorms="false"/> <fieldType name="text_chinese" class="solr.TextField" > <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
够了,启动就行,如果没有错误,那么可以通过控制面板测试一下分词效果:
值得一提的是,不是所有中文都要中文分词的,比如作者名称,这个就不适合做中文分词了,简单一个字符一个字符分开更合适。如果要搜索文档内容,就最好用中文分词效果好很多。
零、Solr于IK 版本不兼容问题
如果你按照上面的方法配置了solr的中文分词后,启动时报如下错误:
1664 [coreLoadExecutor-3-thread-2] ERROR org.apache.solr.core.CoreContainer - null:java.lang.VerifyError: class org.wltea.analyzer.lucene.IKAnalyzer overrides final method tokenStream.
(Ljava/lang/String;Ljava/io/Reader;)Lorg/apache/lucene/analysis/TokenStream;
或者遇到有关BaseTokenizerFactory的报错。
那基本就是你用的IK的版本不是适合SOLR 4.0的版本,严格的说是Luence的4.0版。我用的是IK Analyzer 2012FF_hf1.zip 。对应solr4.3.1,亲测可以使用。
三、如何控制文档评分?
用一个搜索引擎工具最难的地方莫过于熟练控制文档评分规则了,不过这方面我还没有摸透,了解的非常有限,后续不断完善吧。
控制评分由2种方式,第一种比较简单,就是通过在搜索时,设置sort字段,来控制。
solr的查询语法在这里。其中可以看到sort参数的语法规则。这里就不具体介绍了,比如想要先按是否是VIP作者排序,然后按评分排序结果文档:sort=vip desc, score desc 就行了。
另外一种就是通过使用FunctionQuery(不知道怎么翻译)来控制评分规则,里面有很多函数可以用,比如常用的数学函数,字符串函数等。
控制要搜索的字段可以用qf参数来配置,这个上面已经说过了,比如<str name="qf">exactmatch_name^100 namecategory author content</str>,另外一个调整权重的参数是bf, 比如官方文档中有个例子:
q=foo&bf="ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3"
上面哈衣是指关键词为foo,搜索完后,会用bf的表达式,对结果文档的评分进行影响,注意并不是替换,所以上面第一种qf字段还是有作用的。基本就是讲bf字段算出的评分加到原始评分上面。这个名字不太让人能看出是干什么,《Solr 1.4 Enterprise Search Server》作者也有吐槽:
A bad name for this feature
The name of this feature is poor as it does not reflect what it does. Perhaps Scoring Function or even Score Query might have been better. The reason for the name Function Query undoubtedly stems from the manner in which the feature is implemented. It is implemented as a Lucene Query type, albeit a very strange one that matches all of the
documents but scores them differently.
比如如果我想将一本书的weight权重字段加到搜索评分机制里面,权重越高排序相对越前的话,可以这么配置:<str name="bf">log(sum(weight,1))</str>,或者将其表达式的值再变大,这个得看具体需求,进行个性化调整参数了。
FunctionQuery的更多使用细节得多看官方文档和上面的《Solr 1.4 Enterprise Search Server》了,另外develop上也有一些不错的介绍文档,比如:使用 Apache Lucene 和 Solr 进行位置感知搜索。笔者也是初学····
四、如何对字段范围进行控制?
对于书籍搜索这个例子来说,用户搜索可能需要搜外文书,中文书,出版年限控制等,这个可以通过fq参数进行控制,fq=filter query应该。老规矩,具体使用看这里的文档,对了,记得用GOOGLE搜吧,别用百度害自己。
下面举个例子比如我想按书名搜索,搜索没有下架的书记,卖家为官方,价格为50以上的书的话,可以用下面的参数:
start=0&q=趁着年轻&qf=name&json.nl=map&wt=json&fq=invalid:0 uploader:0 valid:[50 TO *]
好了,差不多了,后续碰到什么坑在更新到这里吧。
少碰坑的王道:默念三遍:看文档,看文档,在地铁上看文档······
关于参考文档,直接用超链接的形式提供在文章中了。
您好,关于solr的问题想与您交流一下,不知道是否方便留个联系方式,或加我qq525956272