庖丁(Paoding)分词的词典原理解析

Paoding分词过程中词典是相关重要的一环,其特性主要有:

(1)多词典支持,词典功能区分;

(2)词典加载入内存使用,使用预加载和Lazy Mode模式;

(3)根据分词模式,对词典进行二次编译;

(4)词典变更侦测,当词典文件发生变化时,可以重新加载词典。

1.1     词典类型

庖丁中有多种词典,每一种词典在分词过程中都不有同的意义。主要的词典及其功能如下:

(1)VocabularyDictionary:分词主要的词典,最后构建索引的索引项(term\dictionary);

(2)ConfucianFamilyNamesDictionary:中文姓氏词典,用于识别特殊词;

(3)NoiseCharactorsDictionary:停止单字词典,该词典中的词不用于构建索引项;

(4)NoiseWordsDictionary:停止词语词典,该词典中的词不用于构建索引项;

(5)UnitsDictionary:计量单位词典,该词典中的词主要是一些计量单位。

paoding将多个词典进行组合进行使用。

 

1.2     词典加载流程

1)        PaodingAnalyzer初始化时需要构建Paoding对象;

2)        先由PaodingMaker的readUnCompiledDictionaries调用FileDictionaries;

3)        获取各种属性和词典编译类;

4)        读取未编译词典属性、编译词典(FileDictionaries的一些方法中才真正的加载了词项、CompiledFileDictionaries中调用读取词项);

5)        使用编译后的词典;

6)        为词典设置变更监听器。

1.3     词典文件格式

词典文本一般为纯文本格式,notepad将文件保存为unitcode或utf-8时会在文件开头保存bom字符串,notepad根据是否有bom来识别该文件是否是utf-8编码存储的(详情参见 ref:http://www.w3.org/International/questions/qa-utf8-bom)。而庖丁字典需要将这个字符从词典中去掉。

词典内格式是一行一个词。 

1.4     读取词典文件

如果需要编译,那么读取词典文件是在词典编译前进行。如果不需要编译,则先不加载。

FileDictionaries的一些方法中才真正的加载了词项、CompiledFileDictionaries中调用读取词项。

词典文件读取采用了Lazy Mode,即需要的时候再加载。

 

1.5     词典编译

(1)根据系统参数配置,调用相应的词典编译类,共有两种一种是MostWordsModeDictionariesCompiler类,即最大词量分词方式,另一种是SortingDictionariesCompiler这个是按词的字顺编译的方式;

(2)判断(vocabularyDictionary)词典是否应该编译:检查文件夹中是否在这个文件:.compiled/xxx/.metadata,从中读取词典的元数据,如果编译类、摘要、版本相同,说明经过了编译,则不需要编译;其他情况都需要编译。

(3)最小切分分词词典编译:将词典中的每一个词当作一个可以被分词的字符串,如果该词还可以继续被完全分解为多个词,那么编译后不记录该词。程序分词某个词后将其首尾位置之间的位置都置为true,如果一个词的所有位置都为true那么说明该词能再被完全分解为多词,否则可作为独立词。

(4)SortingDictionariesCompiler其实就是按词在词典中的原序来进行编译,基本不再做其他处理。

(5)readCompliedDictionaries方法返回庖丁中的编译后的多种词典集合。

 

1.6     词典变更侦测

1)变更侦测原理

在创建Paoding时初始化Dictionaries,然后启动Detector利用线程驻守,定期去检测;每一个字典都有一个快照,记录下当前快照,检测时将最新快照与当前快照比对,如果发现不同,那么说明有更新,则触发变更监听DiffListener。更新有三种情况:修改、删除、添加。发现更新后,监听器刷新词典,然后重新为各个Knife设置词典。

 

2)快照原理

快照主要记录了如下信息:

 

// 此次快照版本,使用时间表示

    private long version;

 

    // 根地址,绝对地址,使用/作为目录分隔符

    private String root;

 

    // String为相对根的地址,使用/作为目录分隔符

    private Map/*<String, InnerNode>*/ nodesMap = new HashMap/*<String, InnerNode>*/();

 

    //内部节点

    private InnerNode[] nodes;

    //checksum of this snapshot

    private String checksum;

 

快照刷新方法:获取当前时间作为version,根路径作为root,内部所有的文件作为nodes,然后<相对根的地址,node>作为nodesMap;

快照摘要:采用lazy mode获取快照摘要;

快照对比原理:对比version\root和新增、修改、删除的词典文件(而不是词典中的词)。

猜你喜欢

转载自yingbin920.iteye.com/blog/1575260