digoal
2016-11-09
postgresql , 拼音 , 中文分詞 , tsvector , 拼音首字母 , hmm , 詞庫
postgresql有很多特性是可以提升開發效率,提高生産力的。
在前端頁面中,搜尋是一個非常常用的功能,例如淘寶首頁的搜尋。

為了提升使用者體驗,使用者可以按拼音首字母進行搜尋,按中文單詞搜尋,或者按拼音的全部進行搜尋。
又比如家裡的電視盒子,因為沒有實體鍵盤,按拼音首字母搜尋就非常友善。
但是如何做到按拼音首字母或者按拼音可以進行比對呢?
本文的case主要需要用到的是中文和拼音以及拼音首字母的互相轉換。
例如這樣的轉換
有一個很好的例子
<a href="http://www.letiantian.me/2016-02-08-pinyin-hanzi/">http://www.letiantian.me/2016-02-08-pinyin-hanzi/</a>
詞庫中既要包含每個字的拼音,也要包含常用單詞/短語的讀音。有些字是多音字,是以至少要儲存其最常用的讀音,不常用的讀音多出現在單詞/短語裡。
好了,詞庫準備好了,現在手頭有一句話要轉換要轉換為拼音,這句話是:
我們的詞庫是這樣子的:
詞庫中最長的詞 苦盡甘來 包含4個字。是以 你好世界杯 從4個字開始比對:
判斷你好世界是否在詞庫中,不在;
判斷你好世是否在詞庫中,不在;
判斷你好是否在詞庫中,在,得到nǐ,hǎo;
判斷世界杯是否在詞庫中,不在;
判斷世界是否在詞庫中,在,得到shì,jiè;
判斷杯是否在詞庫中,在,得到bēi;
于是你好世界杯被轉換為nǐ,hǎo,shì,jiè,bēi。
純粹的基于詞庫的方法在實際的使用中會遇到問題,例如 提出了解決方案 這句話中 了解 會被當作一個單詞,是以會得到錯誤的結果:
更好的方法是先進行分詞得到:
然後基于詞庫對每個結果分别處理。
這裡的拼音一般不帶聲調。
将漢字作為隐藏狀态,拼音作為觀測值,使用viterbi算法可以将多個拼音轉換成合理的漢字。例如給出 ti,chu,le,jie,jue,fang,an ,viterbi算法會認為 提出了解決方案 是最合理的狀态序列。
hmm需要三個分布,分别是:
初始時各個狀态的機率分布
各個狀态互相轉換的機率分布
狀态到觀測值的機率分布
這個3個分布就是三個矩陣,根據一些文本庫統計出來即可。
viterbi算法基于動态規劃,維基百科 - viterbi algorithm給出了很好的解釋和示例。
原則:
詞的權重大于字的權重;
轉換中比對的詞越多,權重越小。
詞庫的格式是:
例如:
假如輸入是 ni,hao,a ,我們計算一下各種組合的權重:
組合
權重
你,好,啊
0.15×0.14×0.18 = 0.00378
泥,好,啊
0.12×0.14×0.18 = 0.003024
你好,啊
0.6×0.18 = 0.108
可以看出,你好,啊 是最好的結果。
實際實作中需要用到動态規劃, 和求有向無環圖中兩點之間最短距離類似。
基于上面的思路,我編寫了兩個工具,歡迎指教 ^^
<a href="https://github.com/jmz331/gpinyin">https://github.com/jmz331/gpinyin</a>
<a href="https://github.com/letiantian/pinyin2hanzi">https://github.com/letiantian/pinyin2hanzi</a>
<a href="https://github.com/letiantian/chinesetone">https://github.com/letiantian/chinesetone</a>
<a href="http://www.pudn.com/downloads370/sourcecode/windows/ime/detail1600247.html">http://www.pudn.com/downloads370/sourcecode/windows/ime/detail1600247.html</a>
可以把相關的中文,拼音互相轉換的代碼,嫁接到postgresql,作為udf對外提供轉換接口。
例如輸入 zh_to_pinyin('你好') 傳回 nihao,nh
或者可以結合中文分詞一起使用,同時支援自定義delimiter。
例如輸入 zh_to_pinyin('你好中國漢字', ';', ',') 傳回 nihao,nh;zhongguo,zg;hanzi,hz
1. 首先我們應該考慮分詞,例如使用者輸入一個字元串,傳回分詞後的word。
例如
2. 然後對word進行轉換,得到轉換後的值。
例如輸入 zh_to_pinyin(to_tsvector('zhparser', '你好中國')) 傳回 你好,中國,nihao,nh,zhongguo,zg
使用postgresql分詞插件得到分詞的例子《使用阿裡雲postgresql zhparser時不可不知的幾個參數》
<a href="https://yq.aliyun.com/articles/7730">https://yq.aliyun.com/articles/7730</a>
這些動作可以封裝為一個udf來執行,提升效率,減少互動次數。
3. 得到轉換後的值之後,再存入對應的字段中。
在postgresql中,你可以選擇存儲為字元串數組,或者tsvector類型。
這兩種類型都支援包含的查詢。
1. 精确比對
2. 操作符
數組
tsvector