微信團隊分享:微信移動端的全文檢索多音字問題解決方案
本文來自微信開發團隊WeMobileDev公眾號的技術分享。
1、前言
微信的移動客戶端全文搜尋中的多音字問題一直是搜尋體驗的痛點之一。微信客戶端全文搜尋在上線以後,也經常收到使用者關於多音字問題的反饋。所以,微信全文搜尋中的多音字搜尋成了一個迫切需要解決的問題。本文重點講述微信安卓客戶端在SQLite FTS5的基礎上,多音字問題的解決方案。
另外:微信團隊在另一個文章《微信手機端的本地資料全文檢索優化之路》 中,分享了更為詳細的全文檢索優化思路,建議有興趣的開發者可以深入的看看。
建議:您也可以在微信客戶端的sqlite資料庫中找到本文中相關技術的真實實現,微信的SQLite樣本庫可在此下載《微信本地資料庫破解版(含iOS、Android),僅供學習研究 [附件下載]》(特別申明:微信的SQLite樣本庫僅供研究和學習之外,嚴禁用於商用業目的,所有權歸微信所有)。
學習交流:
– 即時通訊開發交流群:320837163[推薦]
– 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
(本文同步釋出於:http://www.52im.net/thread-1545-1-1.html)
2、相關文章
《騰訊技術分享:Android版手機QQ的快取監控與優化實踐》
《微信團隊分享:iOS版微信的高效能通用key-value元件技術實踐》
《微信團隊分享:iOS版微信是如何防止特殊字元導致的炸群、APP崩潰的?》
《騰訊技術分享:Android手Q的執行緒死鎖監控系統技術實踐》
《騰訊團隊分享 :一次手Q聊天介面中圖片顯示bug的追蹤過程分享》
《微信團隊披露:微信介面卡死超級bug“15。。。。”的來龍去脈》
《微信客戶端團隊負責人技術訪談:如何著手客戶端效能監控和優化》
《微信團隊原創分享:微信客戶端SQLite資料庫損壞修復實踐》
《移動端IM實踐:Android版微信如何大幅提升互動效能(一)》
《移動端IM實踐:Android版微信如何大幅提升互動效能(二)》
《信鴿團隊原創:一起走過 iOS10 上訊息推送(APNS)的坑》
3、微信的全文檢索需求
搜尋形式:
拼音字首搜尋,中文和拼音不能混合搜尋,輸入拼音必須為連續漢字的全拼音或者短拼音。
搜尋內容:
聯絡人、群聊以及公眾號的備註和暱稱(最大長度為16箇中文字元)。
例如。
聯絡人A,暱稱為“王巨集偉”,那麼通過以下幾種方式都需要搜尋到聯絡人A的暱稱:
4、詞表方案
中文全文搜尋引擎如果需要支援拼音,就需要把輸入的中文字元,轉化為拼音字母,如果不考慮多音字的情況,我們只需要一張單個漢字的拼音表即可實現轉化,但是在多音字的情況下,由於每個漢字在不同的詞語當中的讀音都有可能不一樣,所以,為了使得每個中文字元能夠獲取到準確的拼音,就需要引入一份詞語拼音對應表。
眾所周知,漢語博大精深,常用的漢字有20777個,而詞語(包括成語)的漢字個數為2到16個,同一個漢字在不同詞語中讀音有可能不一樣。
所以漢語詞語轉化為拼音有如下兩個方案:
1)窮舉詞語表;
2)採用概率模型,通過訓練分類器模型,獲取中文字元拼音。
第一種方案對儲存空間的要求非常高,對資源的消耗過大。
第二種方案,通過在現有的TTS(Text To Speech)模型中,把漢字轉拼音讀音的模型拆出來,初步搭建一個概率模型,在初步的調優後,得到一個1個G的拼音模型,識別拼音的準確在可接受範圍內。由於模型大小為GB級別,初步考慮是將模型放到後臺處理。
處理流程如下圖:
優點:
客戶端無改動,可以快速覆蓋所有版本客戶端。
缺點:
使用者修改備註或者暱稱後,需要等待後臺下發拼音後才能有正確的拼音索引,導致拼音索引建立不夠及時。微信使用者量巨大,使用者修改備註和暱稱的頻次非常高,每天都有幾十億次修改,導致後臺處理這部分的運算量和耗時非常嚴重,需要增加較大成本。
5、字表方案
常用漢字有20777個,總體大小為200KB,可以直接帶到客戶端中,並且查詢的時間複雜度為O(1),在資料量方面是可以接受的。
優點:
使用者修改暱稱或者備註以後,能夠快速響應並及時建立索引;
將後臺巨大的計算量均攤到使用者手機上,節省成本;
對於姓名中漢字的讀音,可以用任意一個讀音搜尋出來。
缺點:
在使用者體驗上,詞語中的多音字可以用任意該漢字的拼音搜尋出來;
在綜合考慮使用者體驗和效能問題後,最後微信選擇了字表方案。
6、客戶端索引方案
在確定字表方案後,需要在客戶端本地使用SQLite FTS5建立索引。因為拼音搜尋主要是採用字首搜尋的方式,所以建立索引的內容以及方式需要考慮FTS5字首搜尋的過程。
路徑(1)是在建立索引表時使用Prefix索引,所以使用者在輸入Query時,直接通過Hash方法查詢字首索引表即可找到所有以Query為字首的結果。
路徑(2)是在建立索引表時未使用Prefix索引,所以使用者在輸入Query時,FTS5通過臨時搭建一個字首樹來查詢以Query為Preifx的索引集合。
從時間複雜度上,路徑1具有明顯優勢,所以在建立索引時,需要加入Prefix配置:
6.1 索引方案一
考慮到使用者輸入時是連續輸入,並不會考慮跨拼音問題。
例如,使用者搜尋備註“市委書記”的拼音,會可能採用如下的Query:
shi
shiweishuj
sw
根據以上使用者輸入習慣以及FTS5字首搜尋原理,採用第一個索引方案:
在FTS5匹配以上Query時,使用者1、2兩種輸入都作為”shiweishuji”的字首被匹配,而3的輸入會作為“swsj”的字首被匹配。
6.2 索引方案二
索引方案一僅考慮使用者從拼音的頭部開始搜尋,並沒有考慮從中間開始搜尋。
例如以下的Query:
shuji
sj
所以,需要建立索引時,需要把每個漢字的拼音作為字首建立到索引中,如下表:
6.3 索引方案三
方案一和方案二是在不考慮多音字的情況的索引方案,當引入了多音字以後,在組合拼音字串時,每一個拼音都可能存在多種情況。
以下為使用者備註“張靚穎”的索引:
當暱稱“張靚穎”建立索引以後,得到如下索引結構:
TermOffset:表示一個詞語在某一個Document中的偏移;
DocId:Document的唯一ID。
通過一個DocId和一個TermOffset可以定位一個詞語。而SQLite FTS5正是通過搜尋一個詞語來找到對應的DocId,通過TermOffset來定位該詞語在Document中的位置。
方案優點:
實現較為簡單;
可覆蓋所有多音字情況。
方案缺點:
索引資料量過大;
考慮常用漢字一共20777個,其中多音字2659個,多音字佔比12.7%,平均每個多音字有2.14個拼音。
在微信場景中,聯絡人的備註和暱稱最大字元長度為16個字元,所以我們假設每個暱稱的字元為16個漢字,其中,每個漢字的拼音長度為最長度(7個英文字母+1個短拼音英文字母)。
一般場景:
其中20777個漢字當中,出現在暱稱中的概率一樣,所以16個字元中,大約會出現3個多音字,得到如下公式:
極限場景:
暱稱中每一個字都是多音字,每個多音字都有4個讀音,例如“麼麼麼麼麼麼麼麼麼麼麼麼麼麼麼麼”,得到如下公式:
從以上兩種場景中可以看出,方案三在極限場景中會出現佔用超大資料量的情況,所以方案三不可用。
6.4 索引方案四
方案三通過窮舉法來列舉所有拼音組合,核心在於通過空間換區時間,在所需要的空間過於巨大時,可以採取折中的方案來實現。
在漢語中,一個同樣意義的實體通過兩個不同的詞語來表示,稱這兩個不同的詞語為同義詞,在資料上表示為(詞語A,詞語B)=(意義C),那麼在多音字的情況來看,同樣可以表示為(拼音A,拼音B)=(漢字C)。方案四的核心在於通過同義詞的方式來表示多種拼音的組合。
在SQLite FTS5中,一個詞語可以通過一個DocId和一個TermOffset來定位,所以當兩個詞語擁有同一個DocId和TermOffset時,就可以說這兩個詞語為同義詞了,也就有了如下的索引方案:
方案優點:
索引資料量小:
1)一般情況:
2)極限情況:
建立索引速度快。
方案缺點:
預設分詞器不能適配多音字的拼音資料;
索引中的資料不能直接對應使用者輸入。
為了解決方案四的兩個問題,我們引入了多音字分詞器,並且做了使用者輸入預處理。
7、多音字分詞器
SQLite FTS5預設的分詞器的分隔符都是固定的,所以,在識別拼音字元時,會當成英文字母來分詞。為了能夠達到需要的索引結構,我們引入了二級分隔符,使用分號“;”分隔不同漢字以及“,”分隔同一個漢字的不同拼音。
以下是多音字分詞器的分詞流程:
8、使用者輸入預處理
當使用者的輸入為連續拼音時,由於索引中不存在直接對應的Term,所以需要把使用者輸入的Query拆解成為索引當中可能存在的Term。
假設使用者輸入拼音:zhuang,根據短拼音和全拼音的規則,可得到如下7中搜尋組合:
考慮到最後一個拼音為字首搜尋,所以,在列舉拼音組合時,前面都需要考慮符合完整的拼音,最後一個可以只考慮是否是某個拼音的字首。
實現這個演算法可以通過把所有的拼音作為輸入,構建一顆字首樹,能夠把整個Query拼音拆解的時間複雜度降低到O(nlgn)。
最後,把所有的拼音組合情況都寫到SQL中:
9、方案的實際效果
對比方案三和方案四,在拼音資料上有較為明顯的提升,提升的範圍在50%左右。
由於聯絡人拼音資料的減少,使得單個聯絡人的資料量下降,減少了Insert SQL的執行時間,建立聯絡人索引的時間也有較為明顯的降低,減少30%左右。
在搜尋Query的時間上,多音字方案因為拼音組合的多樣性,增加了查詢HashTable的次數,但是由於搜尋HashTable的時間複雜度為O(1),而拼音組合在有限字元的query下不多(小於20個),所以增加時間不多,但是由於資料量的減少,ORM的時間縮短,搜尋Query的時間有15%左右的提升。
更為詳細的微信全文檢索優化思路請見《微信手機端的本地資料全文檢索優化之路》。微信的本地SQLite研究樣本可從此下載《微信本地資料庫破解版(含iOS、Android),僅供學習研究 [附件下載]》(特別申明:微信的SQLite樣本庫僅供研究和學習之外,嚴禁用於商用業目的,所有權歸微信所有)。
附錄:更多微信、QQ的文章
[1] QQ、微信團隊原創技術文章:
《騰訊技術分享:Android版手機QQ的快取監控與優化實踐》
《微信團隊分享:iOS版微信的高效能通用key-value元件技術實踐》
《微信團隊分享:iOS版微信是如何防止特殊字元導致的炸群、APP崩潰的?》
《騰訊技術分享:Android手Q的執行緒死鎖監控系統技術實踐》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(上篇)》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(下篇)》
《騰訊團隊分享 :一次手Q聊天介面中圖片顯示bug的追蹤過程分享》
《微信團隊分享:微信Android版小視訊編碼填過的那些坑》
《微信團隊披露:微信介面卡死超級bug“15。。。。”的來龍去脈》
《月活8.89億的超級IM微信是如何進行Android端相容測試的》
《微信客戶端團隊負責人技術訪談:如何著手客戶端效能監控和優化》
《微信團隊原創分享:Android版微信的臃腫之困與模組化實踐之路》
《微信團隊原創分享:微信客戶端SQLite資料庫損壞修復實踐》
《騰訊原創分享(一):如何大幅提升行動網路下手機QQ的圖片傳輸速度和成功率》
《騰訊原創分享(二):如何大幅壓縮行動網路下APP的流量消耗(下篇)》
《騰訊原創分享(二):如何大幅壓縮行動網路下APP的流量消耗(上篇)》
《如約而至:微信自用的移動端IM網路層跨平臺元件庫Mars已正式開源》
《開源libco庫:單機千萬連線、支撐微信8億使用者的後臺框架基石 [原始碼下載]》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《微信團隊原創分享:Android版微信後臺保活實戰分享(程式保活篇)》
《微信團隊原創分享:Android版微信後臺保活實戰分享(網路保活篇)》
《Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載]》
《微信團隊原創分享:Android版微信從300KB到30MB的技術演進》
《微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載]》
《微信海量使用者背後的後臺系統儲存架構(視訊+PPT) [附件下載]》
《微信非同步化改造實踐:8億月活、單機千萬連線背後的後臺解決方案》
《架構之道:3個程式設計師成就微信朋友圈日均10億釋出量[有視訊]》
《微信團隊原創分享:Android記憶體洩漏監控和優化技巧總結》
《微信團隊原創Android資源混淆工具:AndResGuard [有原始碼]》
《移動端IM實踐:Android版微信如何大幅提升互動效能(一)》
《移動端IM實踐:Android版微信如何大幅提升互動效能(二)》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
《移動端IM實踐:谷歌訊息推送服務(GCM)研究(來自微信)》
《信鴿團隊原創:一起走過 iOS10 上訊息推送(APNS)的坑》
>> 更多同類文章 ……
[2] 有關QQ、微信的技術故事:
《技術往事:微信估值已超5千億,雷軍曾有機會收編張小龍及其Foxmail》
《2017微信資料包告:日活躍使用者達9億、日發訊息380億條》
《技術往事:創業初期的騰訊——16年前的冬天,誰動了馬化騰的程式碼》
《技術往事:史上最全QQ圖示變遷過程,追尋IM巨人的演進歷史》
《開發往事:深度講述2010到2015,微信一路風雨的背後》
《開發往事:記錄微信3.0版背後的故事(距微信1.0釋出9個月時)》
>> 更多同類文章 ……
(本文同步釋出於:http://www.52im.net/thread-1545-1-1.html)
相關文章
- Android 微信分享後留在微信,沒有回撥的問題解決方案Android
- 微信分享(移動web端)Web
- IM全文檢索技術專題(四):微信iOS端的最新全文檢索技術優化實踐iOS優化
- react解決ios微信分享的問題ReactiOS
- 微信登入-6問題解決方案
- keycloak整合微信登陸~解決國內微信整合的問題
- 乾貨分享——連結被微信停止訪問的解決方案
- 分享微信小說域名防封最新的解決方案
- 微信小程式支付全問題解決微信小程式
- 微信團隊原創分享:Android版微信後臺保活實戰分享(程式保活篇)Android
- vue 微信授權解決方案Vue
- 微信小程式元件化的解決方案微信小程式元件化
- 微信直接下載app的解決方案APP
- iOS 微信支付SDK與微信友盟分享兩者同時整合時,出現的問題與解決之路。iOS
- 移動端滾動穿透問題解決方案穿透
- 移動端適配問題解決方案
- 微信團隊原創分享:iOS版微信的記憶體監控系統技術實踐iOS記憶體
- 微信後團隊分享:微信後臺基於Ray的分散式AI計算技術實踐分散式AI
- Android微信分享圖片按質量壓縮的解決方案Android
- 微信支付團隊釋出“微信青蛙pro” 支援刷臉支付功能
- 微信域名檢測 微信域名檢測官方介面的呼叫程式碼分享
- 微信分享
- 微信分享常見問題--避坑指北
- jquery-weui微信支付報錯問題解決jQueryUI
- 微信內分享連結被封怎麼解決,微信域名防封的工作原理
- 微信團隊分享:微信後臺在海量併發請求下是如何做到不崩潰的
- 適配移動端的問題以及解決方案
- 分享微信域名檢測API介面API
- 微信域名防封技術、微信域名檢測技術的常見問題解答
- 移動端滾動穿透問題完美解決方案穿透
- 【微信小程式】微信小程式 文字過長,自動換行的問題微信小程式
- 微信小程式 unionid 登入解決方案微信小程式
- js在微信、微博、QQ、Safari喚起App的解決方案JSAPP
- 微信提現問題
- 微信內分享域名防紅方案-微信域名防封跳轉技術的方案解析
- 微信小程式動態載入外部字型的完美解決方案微信小程式
- 微信活碼技術如何解決微信群二維碼失效問題
- 微信小程式登入方式的修改解決方案微信小程式