solr 6.5 suggest 自动补全(解决单个字符无结果问题)
solr的日常搜索大家都比较熟悉,稍微提升点的搜索就涉及到了自动补全。下面就亲身测试,说一下自动补全,使用的为solr 6.5版本。
在原有的solr搜索基础上增加自动补全,首先修改solrconfig.xml
searchComponent 为官方wiki的代码,无改动。
<searchComponent class="solr.SpellCheckComponent" name="suggest">
<str name="queryAnalyzerFieldType">text_spell</str>
<lst name="spellchecker">
<str name="name">suggest</str>
<str name="classname">org.apache.solr.spelling.suggest.Suggester</str>
<str name="lookupImpl">org.apache.solr.spelling.suggest.tst.TSTLookup</str>
<str name="field">suggestion</str>
<!-- the indexed field to derive suggestions from -->
<float name="threshold">0.0001</float>
<str name="spellcheckIndexDir">spellchecker</str>
<str name="comparatorClass">freq</str>
<str name="buildOnOptimize">true</str>
<!--<str name="buildOnCommit">true</str>-->
</lst>
</searchComponent>
<requestHandler class="org.apache.solr.handler.component.SearchHandler"
name="/suggest">
<lst name="defaults">
<str name="spellcheck">true</str>
<str name="spellcheck.dictionary">suggest</str>
<str name="spellcheck.onlyMorePopular">true</str>
<str name="spellcheck.extendedResults">false</str>
<str name="spellcheck.count">10</str>
<str name="spellcheck.collate">true</str>
</lst>
<arr name="components">
<str>suggest</str>
</arr>
</requestHandler>
<queryConverter name="phraseQueryConverter" class="org.apache.solr.spelling.SpellingQueryConverter"/>
名称 | 含义 |
---|---|
queryAnalyzerFieldType | schema.xml中的fieldType类型,如果加了这个选项,拼写检查时会调用这个fieldType的分词器,如果没有加,solr会取field属性上面filetype的分词器,这个时候还找不到,solr会创建一个按空格进行分词(SpellCheckComponent需要一个分词器才能运行),在这们项目中,我们现希望Analyzer不对查询做任何的改变,因此选择string。(网上也建议不要对他定义复杂的分词,如果指定的Analyzer很复杂的话,会导致suggest返回的结果不符合预期) |
name | 就是取个名字,江湖中的人士都是让他等于suggest |
classname | org.apache.solr.spelling.suggest.Suggester(不要改动) |
lookupImpl | org.apache.solr.spelling.suggest.tst.TSTLookup(不要改动) |
field | 说明只在这个字段上面做拼写检查 |
threshold | 限制一些不常用的词出现,值越大过滤词就越多,取值范围【0~1】官网默认是0.005 |
comparatorClass | ellchecker组件中的comparatorClass参数可配置Suggest返回结果的排序,目前有如下几种可选方案:1.Empty – in which case the default is used. 默认就是这个;2.score – explicitly choose the default case ;3.freq – Sort by frequency first, then score. 通过频率的第一排序,然后得分 (开发时用这个);4.A fully qualified class name – Provide a custom comparator that implements Comparator |
buildOnCommit | 取值true或者flase当commit的时候,对拼写检查索引进行构建。(只有构建后,拼写检查才有效果) |
buildOnOptimize | 当optimize的时候,对拼写检查索引进行构建。(只有构建后,拼写检查才有效果) |
requestHandler参数含义:
代码 | 含义 |
---|---|
spellcheck | 开启检查建议 |
spellcheck.dictionary | 必须与searchComponent中spellchecker标签下suggest配置对应 |
spellcheck.count | 配置拼写检查提示结果的个数(可以根据需要适当加大) |
spellcheck.onlyMorePopular | 等于true,可以根据权重排序,开发时我一般让他等于true |
spellcheck.collate | 提供一个查询并与第一个匹配的建议, |
components | handler拥有的 components,first-components,last-components这三个属性的剖析Solr的handler都是同过这三个属性来取他所依赖的components(组件)备注:handler在运行时,会加载5个默认的组件1.如果配置了components,则SOlr不会运行默认的5个组件。而且你配置的first-components,last-components两个都是无效的。2.如果配置了first-components,SOlr会给handler添加5个默认的组件时,同时会添加first-components配置的组件,而且这个组件最先工作。3.同上,只不过放在最后工作 |
managed-schema修改
<!-- 单词补全建议-->
<fieldType name="text_spell" class="solr.TextField">
<analyzer type="index">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<!-- 完整词组建议 -->
<fieldType class="solr.TextField" name="text_auto_phrase">
<analyzer>
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<field name="suggestion" type="text_auto_phrase" indexed="true" stored="true" termVectors="true" multiValued="true" />
<copyField source="keyword" dest="suggestion" />
到这配置就完成了。
配置好后,重启solr,导入数据
然后输入suggest
输入单个字符或单个汉字无结果显示解决
查村时加上字段名就可以支持单个字符了
程序调用
/**
*
* 自动建议
* @param keyword 格式为:key:value
* @return
* @author john
* @version 2019年2月26日
*/
protected JSONObject suggest(String keyword) {
QueryResponse resp;
Map<String,List<String>> map=new LinkedHashMap<>();
String collatedResult="";
try {
//获得solr连接客户端的代码请自查百度
HttpSolrClient httpSolrClient = getHttpSolrClient();
SolrQuery query = new SolrQuery(keyword);
resp = httpSolrClient.query(query);
SpellCheckResponse spellCheckResponse = resp.getSpellCheckResponse();
Map<String, SpellCheckResponse.Suggestion> suggestionMap = spellCheckResponse.getSuggestionMap();
for (String key:suggestionMap.keySet()){
SpellCheckResponse.Suggestion suggestion = suggestionMap.get(key);
map.put(key,suggestion.getAlternatives());
}
collatedResult = spellCheckResponse.getCollatedResult();
if (StringUtils.isNotBlank(collatedResult)&&collatedResult.indexOf(":")>-1){
collatedResult=collatedResult.substring(collatedResult.indexOf(":")+1);
}
} catch (Exception e) {
e.printStackTrace();
LogUtils.writeErrLog("SolrBaseSupport", e.getClass().getSimpleName(), "queryCount", e.toString());
}
JSONObject object=new JSONObject();
object.put("suggestions",map);
object.put("recommend",collatedResult);
return object;
}
字段说明参考:https://blog.csdn.net/dandan2zhuzhu/article/details/52025656