?
一、背景
? 搜索的智能提示是一個(gè)搜索應(yīng)用的標(biāo)配,主要作用是避免用戶輸入錯(cuò)誤的搜索詞,并將用戶引導(dǎo)到相應(yīng)的關(guān)鍵詞上,提升用戶體驗(yàn)。
? 由于中文的特點(diǎn),如果搜索自動(dòng)提示可以支持拼音的話會(huì)給用戶帶來更大的方便,免得切換輸入法。
二、目標(biāo)
- 基于用戶的歷史搜索關(guān)鍵字進(jìn)行提示
- 同時(shí)支持漢字,拼音輸入
- 支持前綴匹配,比如輸入“ch”可能提示出“重慶”
- 支持縮寫輸入,比如輸入“cq”能提示出“重慶”
- 多音字支持,比如輸入“chongqing”或者“zhongqing”都能提示出“重慶”
- 輸出結(jié)果,根據(jù)用戶查詢關(guān)鍵字的頻率進(jìn)行排序,暫時(shí)不考慮個(gè)性化需求
三、分析與解決方案
? ? ? ?假設(shè)我們的搜索應(yīng)用是基于solrcloud實(shí)現(xiàn)的,主要是對(duì)商家信息進(jìn)行搜索,包括商家名稱(store_name)、商家地址(address)。
? ? ? ?(1). 用戶每天輸入大量的查詢關(guān)鍵字,我們把查詢的關(guān)鍵字記錄下來,目前通過異步隊(duì)列寫入到mysql中,后期考慮寫入到hbase中
? ? ? ?(2). 用戶輸入的關(guān)鍵字可能是漢字、數(shù)字,英文,拼音,特殊字符等等,由于需要實(shí)現(xiàn)拼音提示,所以我們需要把漢字轉(zhuǎn)換成拼音,java中考慮使用pinyin4j組件實(shí)現(xiàn)轉(zhuǎn)換。
? ? ? ?(3). 漢字轉(zhuǎn)換拼音的過程中,順便提取出拼音縮寫,如“chongqing”,"zhongqing"--->"cq","zq"
? ? ? ?(4). 要支持多音字提示,對(duì)查詢串轉(zhuǎn)換成拼音后,需要實(shí)現(xiàn)一個(gè)全排列組合,考慮到查詢串可能比較長(zhǎng)導(dǎo)致全排列比較的,具體算法需要做限制處理。
?
Solr Suggest實(shí)現(xiàn)智能提示
? ? ?首先Solr作為一個(gè)應(yīng)用廣泛的搜索引擎系統(tǒng),它內(nèi)置了智能提示功能,叫做Suggest模塊。該模塊有兩種可選方案做智能提示:
? ? ? (1)、基于提示詞文本做智能提示
? ? ? (2)、基于索引中得某個(gè)字段建立索引詞庫(kù)做智能提示
? ? ?suggest的配置相對(duì)簡(jiǎn)單, 下面開始寫 主要是使方式,?自定義的建議詞文本,放在跟solrconfig.xml同一級(jí)目錄下即可
? ? ?例如: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詞庫(kù)詞-->
<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 參數(shù)為string,在這不要定義復(fù)雜分詞,如果是根據(jù)某一個(gè)索引字段,意義不大
?3.field字段名,表示基于schema中的某一個(gè)索引字段
?4.threshold限制一些不常用的詞出現(xiàn),值越大過濾紙?jiān)蕉?
?5.sourceLocation用于設(shè)置字典,如果有一個(gè)字典能記錄用戶常搜索的字, 更靈活的控制,可以存放一些高質(zhì)量的 query短語
?6.spellcheckIndexDir如果已經(jīng)設(shè)置spellcheck,那么可以在此制定目錄
?7.字典格式如下
# This is a sample dictionary file.
acquire
accidentally\t2.0
accommodate\t3.0
文本格式utf-8,#開頭表示注釋,被忽略
每一個(gè)詞一行,后面帶權(quán)重
?8.配置詞典后在requestHandler中設(shè)置spellcheck.onlyMorePopular為true,可以根據(jù)權(quán)重排序
?9.spellcheck.count返回行
??配置完成重啟服務(wù)后,設(shè)置參數(shù)suggest/?spellcheck.build=true來創(chuàng)建spellchecker的索引
?然后輸入:http://ip:port/corename/suggest?q=xxx進(jìn)行搜索了
?接下來就是前臺(tái)js實(shí)現(xiàn)的問題了。
?當(dāng)然也可以通過solrj來進(jìn)行搜索
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(
"查詢耗時(shí):" +
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
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

