一、背景
搜索的智能提示是一个搜索应用的标配,主要作用是避免用户输入错误的搜索词,并将用户引导到相应的关键词上,提升用户体验。
由于中文的特点,如果搜索自动提示可以支持拼音的话会给用户带来更大的方便,免得切换输入法。
二、目标
- 基于用户的历史搜索关键字进行提示
- 同时支持汉字,拼音输入
- 支持前缀匹配,比如输入“ch”可能提示出“重庆”
- 支持缩写输入,比如输入“cq”能提示出“重庆”
- 多音字支持,比如输入“chongqing”或者“zhongqing”都能提示出“重庆”
- 输出结果,根据用户查询关键字的频率进行排序,暂时不考虑个性化需求
三、分析与解决方案
假设我们的搜索应用是基于solrcloud实现的,主要是对商家信息进行搜索,包括商家名称(store_name)、商家地址(address)。
(1). 用户每天输入大量的查询关键字,我们把查询的关键字记录下来,目前通过异步队列写入到mysql中,后期考虑写入到hbase中
(2). 用户输入的关键字可能是汉字、数字,英文,拼音,特殊字符等等,由于需要实现拼音提示,所以我们需要把汉字转换成拼音,java中考虑使用pinyin4j组件实现转换。
(3). 汉字转换拼音的过程中,顺便提取出拼音缩写,如“chongqing”,"zhongqing"--->"cq","zq"
(4). 要支持多音字提示,对查询串转换成拼音后,需要实现一个全排列组合,考虑到查询串可能比较长导致全排列比较的,具体算法需要做限制处理。
Solr Suggest实现智能提示
首先Solr作为一个应用广泛的搜索引擎系统,它内置了智能提示功能,叫做Suggest模块。该模块有两种可选方案做智能提示:
(1)、基于提示词文本做智能提示
(2)、基于索引中得某个字段建立索引词库做智能提示
suggest的配置相对简单, 下面开始写 主要是使方式, 自定义的建议词文本,放在跟solrconfig.xml同一级目录下即可
例如:solr\solr_home\collections\collection1\conf\suggest.txt
下面给出suggest在solrconfig.xml里配置的代码( 中文信息注意删去 ) 配置如下:
<searchComponent name="suggest"
class
="solr.SpellCheckComponent">
<str name="queryAnalyzerFieldType">string</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">my_word</str>
<
float
name="threshold">0.0001</
float
>
<!--
使用自定义suggest词库词-->
<str name="sourceLocation">suggest.txt</str>
<str name="spellcheckIndexDir">spellchecker</str>
<str name="comparatorClass">freq</str>
<str name="buildOnOptimize">
true
</str>
<str name="buildOnCommit">
true
</str>
</lst>
</searchComponent>
<requestHandler name="/suggest"
class
="org.apache.solr.handler.component.SearchHandler">
<lst name="defaults">
<str name="spellcheck">
true
</str>
<str name="spellcheck.dictionary">suggest</str>
<str name="spellcheck.count">10</str>
<str name="spellcheck.onlyMorePopular">
true
</str>
<str name="spellcheck.extendedResults">
false
</str>
<str name="spellcheck.collate">
true
</str>
<!--<str name="spellcheck.build">
true
</str> -->
</lst>
<arr name="components">
<str>suggest</str>
</arr>
</requestHandler>
说明:
1.solr的suggest基于solr.SpellCheckComponent
2.queryAnalyzerFieldType 参数为string,在这不要定义复杂分词,如果是根据某一个索引字段,意义不大
3.field字段名,表示基于schema中的某一个索引字段
4.threshold限制一些不常用的词出现,值越大过滤纸越多
5.sourceLocation用于设置字典,如果有一个字典能记录用户常搜索的字, 更灵活的控制,可以存放一些高质量的 query短语
6.spellcheckIndexDir如果已经设置spellcheck,那么可以在此制定目录
7.字典格式如下
# This is a sample dictionary file.
acquire
accidentally\t2.0
accommodate\t3.0
文本格式utf-8,#开头表示注释,被忽略
每一个词一行,后面带权重
8.配置词典后在requestHandler中设置spellcheck.onlyMorePopular为true,可以根据权重排序
9.spellcheck.count返回行
配置完成重启服务后,设置参数suggest/?spellcheck.build=true来创建spellchecker的索引
然后输入:http://ip:port/corename/suggest?q=xxx进行搜索了
接下来就是前台js实现的问题了。
当然也可以通过solrj来进行搜索
CommonsHttpSolrServer server =
new
CommonsHttpSolrServer(
"http://ip:port/corename/"
);
SolrQuery params
=
new
SolrQuery();
String token
= "Solr"
;
params.set(
"qt", "/suggest"
);
params.set(
"q"
, token);
params.set(
"spellcheck.build", "true"
);
QueryResponse response
=
null
;
try
{
response
=
server.query(params);
System.out.println(
"查询耗时:" +
response.getQTime());
}
catch
(SolrServerException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
catch
(Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
finally
{
}
SpellCheckResponse spellCheckResponse
=
response
.getSpellCheckResponse();
if
(spellCheckResponse !=
null
) {
List
<Suggestion> suggestionList =
spellCheckResponse
.getSuggestions();
for
(Suggestion suggestion : suggestionList) {
System.out.println(
"Suggestions NumFound: "
+
suggestion.getNumFound());
System.out.println(
"Token: " +
suggestion.getToken());
System.out.print(
"Suggested: "
);
List
<String> suggestedWordList =
suggestion.getAlternatives();
for
(String word : suggestedWordList) {
System.out.println(word
+ ", "
);
}
System.out.println();
}
}
-----OK

