单词词典里面基本只要保存词的词性的频率,另外考虑到一次性把词典读入内存的消耗太大,必须把词典分块,当有需求的时候才将特定
的块装载进内存中。在这样的需求下,设计采用如下结构的词典:
+-------------+
| 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