?
一、背景
? 搜索的智能提示是一個(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ì)您有幫助就好】元
