搜索引擎關(guān)鍵字智能提示的一種實(shí)現(xiàn)

問題背景
搜索關(guān)鍵字智能提示是一個(gè)搜索應(yīng)用的標(biāo)配,主要作用是避免用戶輸入錯(cuò)誤的搜索詞嫌褪,并將用戶引導(dǎo)到相應(yīng)的關(guān)鍵詞上胚股,以提升用戶搜索體驗(yàn)裙秋。
醫(yī)口袋服務(wù)中存在數(shù)以百萬計(jì)的內(nèi)容,為了讓用戶快速查找到目標(biāo)內(nèi)容摘刑,我們可以基于solrcloud實(shí)現(xiàn)了內(nèi)容搜索模塊。為了提升用戶的搜索體驗(yàn)和輸入效率党晋,本文實(shí)現(xiàn)了一種基于solr前綴匹配查詢關(guān)鍵字智能提示(Suggestion)實(shí)現(xiàn)徐块。

需求分析
1.支持前綴匹配原則
在搜索框中輸入“海底”,搜索框下面會(huì)以海底為前綴胡控,展示“海底撈”、“海底撈火鍋”昼激、“海底世界”等等搜索詞;輸入“萬達(dá)”瞧掺,會(huì)提示“萬達(dá)影城”凡傅、“萬達(dá)廣場”、“萬達(dá)百貨”等搜索詞像捶。

2.同時(shí)支持漢字、拼音輸入
由于中文的特點(diǎn)释簿,如果搜索自動(dòng)提示可以支持拼音的話會(huì)給用戶帶來更大的方便硼莽,免得切換輸入法煮纵。比如偏螺,輸入“haidi”提示的關(guān)鍵字和輸入“海底”提示的一樣,輸入“wanda”與輸入“萬達(dá)”提示的關(guān)鍵字一樣套像。

3.支持多音字輸入
提示比如輸入“chongqing”或者“zhongqing”都能提示出“重慶火鍋”、“重慶烤魚”贞让、“重慶小天鵝”柳譬。

4.支持拼音縮寫輸入
對于較長關(guān)鍵字,為了提高輸入效率美澳,有必要提供拼音縮寫輸入。比如輸入“hd”應(yīng)該能提示出“haidi”相似的關(guān)鍵字舅桩,輸入“wd”也一樣能提示出“萬達(dá)”關(guān)鍵字。

5.基于用戶的歷史搜索行為江咳,按照關(guān)鍵字熱度進(jìn)行排序
為了提供suggest關(guān)鍵字的準(zhǔn)確度哥放,最終查詢結(jié)果,根據(jù)用戶查詢關(guān)鍵字的頻率進(jìn)行排序甥雕,如輸入[重慶,chongqing,cq,zhongqing,zq] —> [“重慶火鍋”(f1),“重慶烤魚”(f2),“重慶小天鵝”(f3),…]挟阻,查詢頻率f1 > f2 > f3峭弟。

解決方案
關(guān)鍵字收集當(dāng)用戶輸入一個(gè)前綴時(shí),碰到提示的候選詞很多的時(shí)候瞒瘸,如何取舍,哪些展示在前面省撑,哪些展示在后面?這就是一個(gè)搜索熱度的問題竟秫。用戶在使用搜索引擎查找商家時(shí),會(huì)輸入大量的關(guān)鍵字趾浅,每一次輸入就是對關(guān)鍵字的一次投票拙吉,那么關(guān)鍵字被輸入的次數(shù)越多,它對應(yīng)的查詢就比較熱門筷黔,所以需要把查詢的關(guān)鍵字記錄下來仗颈,并且統(tǒng)計(jì)出每個(gè)關(guān)鍵字的頻率,方便提示結(jié)果按照頻率排序请祖。搜索引擎會(huì)通過日志文件把用戶每次檢索使用的所有檢索串都記錄下來脖祈,每個(gè)查詢串的長度為1-255字節(jié)。

漢字轉(zhuǎn)拼音用戶輸入的關(guān)鍵字可能是漢字盖高、數(shù)字,英文席纽,拼音撞蚕,特殊字符等等,由于需要實(shí)現(xiàn)拼音提示甥厦,我們需要把漢字轉(zhuǎn)換成拼音,java中考慮使用pinyin4j組件實(shí)現(xiàn)轉(zhuǎn)換舶赔。

拼音縮寫提取考慮到需要支持拼音縮寫庙洼,漢字轉(zhuǎn)換拼音的過程中镊辕,順便提取出拼音縮寫蚁袭,如“chongqing”,"zhongqing"--->"cq",”zq”。

多音字全排列要支持多音字提示揩悄,對查詢串轉(zhuǎn)換成拼音后,需要實(shí)現(xiàn)一個(gè)全排列組合亏娜,
索引與前綴查詢

方案一: Solr自帶Suggest智能提示Solr作為一個(gè)應(yīng)用廣泛的搜索引擎系統(tǒng)蹬挺,它內(nèi)置了智能提示功能,叫做Suggest模塊巴帮。該模塊可選擇基于提示詞文本做智能提示榕茧,還支持通過針對索引的某個(gè)字段建立索引詞庫做智能提示。 (詳見solr的wiki頁面http://wiki.apache.org/solr/Suggester)
該方案存在的問題是:
返回的結(jié)果是基于索引中字段的詞頻進(jìn)行排序用押,不是用戶搜索關(guān)鍵字的頻率,因此不能將一些熱門關(guān)鍵字排在前面池充。
拼音提示官觅,多音字,縮寫還是要另外加索引字段休涤。

方案二: Solrcloud建立單獨(dú)的collection,利用solr前綴查詢實(shí)現(xiàn)**如前所述功氨,以上兩個(gè)方案在實(shí)施起來都存在一些問題,Trie樹+TopK算法捷凄,在處理漢字suggest時(shí)不是很優(yōu)雅,且需要維護(hù)兩棵Trie樹匈睁,實(shí)施起來比較復(fù)雜;Solr自帶的suggest智能提示組件存在問題是使用freq排序算法航唆,返回的結(jié)果完全基于索引中字符的出現(xiàn)次數(shù),沒有兼顧用戶搜索詞語的頻率糯钙,因此無法將一些熱門詞排在更靠前的位置任岸。于是,我們繼續(xù)尋找一種解決這個(gè)問題更加優(yōu)雅的方案享潜。
至此,我們考慮專門為關(guān)鍵字建立一個(gè)索引collection窝革,利用solr前綴查詢實(shí)現(xiàn)吕座。solr中的copyField能很好解決我們同時(shí)索引多個(gè)字段(漢字瘪板、pinyin, abbre)的需求吴趴,且field的multiValued屬性設(shè)置為true時(shí)能解決同一個(gè)關(guān)鍵字的多音字組合問題侮攀。配置如下:

schema.xml:
<field name="kw" type="string" indexed="true" stored="true" />
<field name="pinyin" type="string" indexed="true" stored="false" multiValued="true"/>
<field name="abbre" type="string" indexed="true" stored="false" multiValued="true"/>
<field name="kwfreq" type="int" indexed="true" stored="true" />
<field name="version" type="long" indexed="true" stored="true"/>
<field name="suggest" type="suggest_text" indexed="true" stored="false" multiValued="true" />
------------------multiValued表示字段是多值的-------------------------------------
<uniqueKey>kw</uniqueKey>
<defaultSearchField>suggest</defaultSearchField>

說明:
kw為原始關(guān)鍵字
pinyin和abbre的multiValued=true,在使用solrj建此索引時(shí)兰英,定義成集合類型即可:如關(guān)鍵字“重慶”的pinyin字段為{chongqing,zhongqing}, abbre字段為{cq, zq}
kwfreq為用戶搜索關(guān)鍵的頻率,用于查詢的時(shí)候排序


<copyField source="kw" dest="suggest" />
<copyField source="pinyin" dest="suggest" />
<copyField source="abbre" dest="suggest" />

------------------suggest_text----------------------------------

<fieldType name="suggest_text" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
<analyzer type="index">
<tokenizer class="solr.KeywordTokenizerFactory" />
<filter class="solr.SynonymFilterFactory"
synonyms="synonyms.txt"
ignoreCase="true"
expand="true" />
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true" />
<filter class="solr.LowerCaseFilterFactory" />
<filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt" />
</analyzer>
<analyzer type="query">
<tokenizer class="solr.KeywordTokenizerFactory" />
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true" />
<filter class="solr.LowerCaseFilterFactory" />
<filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt" />
</analyzer>
</fieldType>

KeywordTokenizerFactory:這個(gè)分詞器不進(jìn)行任何分詞陨闹!整個(gè)字符流變?yōu)閱蝹€(gè)詞元薄坏。String域類型也有類似的效果,但是它不能配置文本分析的其它處理組件君账,比如大小寫轉(zhuǎn)換沈善。任何用于排序和大部分Faceting功能的索引域椭蹄,這個(gè)索引域只有能一個(gè)原始域值中的一個(gè)詞元净赴。
前綴查詢構(gòu)造:
private SolrQuery getSuggestQuery(String prefix, Integer limit) {
SolrQuery solrQuery = new SolrQuery();
StringBuilder sb = new StringBuilder();
sb.append(“suggest:").append(prefix).append("*");
solrQuery.setQuery(sb.toString());
solrQuery.addField("kw");
solrQuery.addField("kwfreq");
solrQuery.addSort("kwfreq", SolrQuery.ORDER.desc);
solrQuery.setStart(0);
solrQuery.setRows(limit);
return solrQuery;
}

效果如下圖所示:
美團(tuán)前端架構(gòu)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市埋酬,隨后出現(xiàn)的幾起案子烧栋,更是在濱河造成了極大的恐慌,老刑警劉巖审姓,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魔吐,死亡現(xiàn)場離奇詭異,居然都是意外死亡酬姆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進(jìn)店門骨宠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來相满,“玉大人,你說我怎么就攤上這事立美。” “怎么了碌更?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵躲撰,是天一觀的道長。 經(jīng)常有香客問我拢蛋,道長,這世上最難降的妖魔是什么快压? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮坪郭,結(jié)果婚禮上脉幢,老公的妹妹穿的比我還像新娘。我一直安慰自己嫌松,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布液走。 她就那樣靜靜地躺著贾陷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪髓废。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天砸喻,我揣著相機(jī)與錄音蒋譬,去河邊找鬼愉适。 笑死,一個(gè)胖子當(dāng)著我的面吹牛维咸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播癌蓖,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼租副,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了用僧?” 一聲冷哼從身側(cè)響起赞咙,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤糟港,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后速和,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剥汤,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年慈迈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了省有。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蠢沿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恤磷,到底是詐尸還是另有隱情,我是刑警寧澤野宜,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布扫步,位于F島的核電站,受9級特大地震影響匈子,放射性物質(zhì)發(fā)生泄漏河胎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一虎敦、第九天 我趴在偏房一處隱蔽的房頂上張望游岳。 院中可真熱鬧,春花似錦其徙、人聲如沸胚迫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春朗若,著一層夾襖步出監(jiān)牢的瞬間恼五,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工哭懈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灾馒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓遣总,卻偏偏與公主長得像睬罗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子旭斥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容