單詞詞典裡面基本只要儲存詞的詞性的頻率,另外考慮到一次性把詞典讀入記憶體的消耗太大,必須把詞典分塊,當有需求的時候才將特定
的塊裝載進記憶體中。在這樣的需求下,設計採用如下結構的詞典:
+-------------+
| Header | -----> 包括詞數量,總頻率,索引開頭位置,索引大小等
+-------------+
| Index | -----> 每個索引項目對應於一個詞表塊。索引項目指示了詞表塊的位置大小等資訊。
+-------------+
| Blocks | -----> 以首字分區的塊。
+-------------+
建立完成的單詞詞典有4Mb,180k+的單詞。大概足夠了。
接下來要建立短語詞典了。這個稍微麻煩一點。手頭上的材料有一大堆網上的新聞。原則上把這些新聞進行分詞,然後把兩兩鄰接的詞拼湊在一起,再將結果進行統計就可以了。但麻煩在於手頭上沒有好的分詞演算法,而且如果按照某一種分詞方法對句子分詞,必然使得到的短語字典的統計機率和該分詞演算法的行為高度一致,就失去了一般性。考慮再三,決定不採用任何方法進行預分詞。直接暴力一點,把句子裡所有可能的分詞都找出來,一起統計其機率。在大量語料的協助下,不合理的短語或詞的組合應該有較低的出現機率,可以在最終根據機率大小進行篩選的時候把它們去掉。
第一版短語字典選用了大概130M作用的新聞作為語言來源。python的效率實在稱不上高,第一次運行用了30+分鐘,記憶體使用量更是驚人的達到1G+。字典裡面短語的有一百多萬,我原以為每個短語需要的位元組數大概為短語的長度加上一些字典和資料結構的開銷,大概幾十位元組,一共也就一兩百個M的記憶體消耗。照這趨勢我那3G記憶體可受不了。。。一開始我還以為什麼地方有泄漏,不過用gc模組查看後發現記憶體的使用挺正常,猜想大概是python的dict使用效率不高吧。。。
為了驗證猜想,寫了一段小程式進行實驗。簡單的說就是往一個字典裡面不斷的添加資料,然後觀察記憶體的使用。字典的key是不大於10的字串,value是4位元組int。加上一些儲存用指標之類,每組資料本身使用的記憶體應該在30位元組左右。然後運行程式,配合task manager看記憶體的使用(進階一點的方法是heapy)。當字典裡的資料個數達到8m個的時候,記憶體使用量了700M+,大約每個資料100個位元組。
看來的確是python的記憶體消耗要超過我的預期。這樣一來就只能從節省記憶體上下功夫了。好在一開始設計字典儲存結構的時候就考慮到記憶體佔用的問題,只要字典存進了磁碟,之後的資料可以load on demand。於是在建立字典的時候周期性的存檔,這樣雖然會付出一些存檔的開銷,記憶體的使用可以降低不少。再次運行,峰值記憶體佔用400M左右,更重要的是隨著資料的增多,記憶體使用量增長的速度逐漸層慢,而不是原來的近乎線性增長了。
最終獲得的短語詞典包含7.3m個項,平均出現頻率為4.2。對短語的出現頻率進行統計,結果有4.8m個短語出現次數為1,1.5m個短語出現次數為2或3。由於我們採用的策略,這些短語很有可能是一些錯誤分詞的結果,或者是一些不常見詞。為了減少詞典的體積,這6.3m個資料直接被忽略,詞典的體積被縮小到原來的1/7,大約10mb。
以下列舉了幾個不同頻率的短語:
的時候: 16134
我們的: 8483
都沒有: 4057
是非常: 2346
也已經: 1091
都應該: 562