中文分词算法 之 词典机制性能优化与测试

在以前的两篇博文中文分词算法 之 基于词典的正向最大匹配算法中文分词算法 之 基于词典的逆向最大匹配算法中,咱们对分词实现词典实现都作了优化,本文对词典实现作进一步优化,并和以前的多个实现作一个对比,使用的词典下载地址,使用的测试文本下载地址java

 

优化TrieV3的关键在于把虚拟根节点(/)的子节点(词表首字母)提高为多个相互独立的根节点,并对这些根节点创建索引。优化的依据是根节点(词表首字母)的数量庞大,索引查找的速度远远超过二分查找git

 

下面看看进一步优化后的TrieV4和以前的TrieV3的对比:github



    /**
     * 获取字符对应的根节点
     * 若是节点不存在
     * 则增长根节点后返回新增的节点
     * @param character 字符
     * @return 字符对应的根节点
     */
    private TrieNode getRootNodeIfNotExistThenCreate(char character){
        TrieNode trieNode = getRootNode(character);
        if(trieNode == null){
            trieNode = new TrieNode(character);
            addRootNode(trieNode);
        }
        return trieNode;
    }
    /**
     * 新增一个根节点
     * @param rootNode 根节点
     */
    private void addRootNode(TrieNode rootNode){
        //计算节点的存储索引
        int index = rootNode.getCharacter()%INDEX_LENGTH;
        //检查索引是否和其余节点冲突
        TrieNode existTrieNode = ROOT_NODES_INDEX[index];
        if(existTrieNode != null){
            //有冲突,将冲突节点附加到当前节点以后
            rootNode.setSibling(existTrieNode);
        }
        //新增的节点老是在最前
        ROOT_NODES_INDEX[index] = rootNode;
    }
    /**
     * 获取字符对应的根节点
     * 若是不存在,则返回NULL
     * @param character 字符
     * @return 字符对应的根节点
     */
    private TrieNode getRootNode(char character){
        //计算节点的存储索引
        int index = character%INDEX_LENGTH;
        TrieNode trieNode = ROOT_NODES_INDEX[index];
        while(trieNode != null && character != trieNode.getCharacter()){
            //若是节点和其余节点冲突,则须要链式查找
            trieNode = trieNode.getSibling();
        }
        return trieNode;
    }

 

 不一样的字符可能会映射到同一个数组索引(映射冲突),因此须要给TrieNode增长一个引用sibling,当冲突发生的时候,可利用该引用将多个冲突元素连接起来,这样,在一个数组索引中就能存储多个TrieNode。若是冲突大量发生,不但会浪费已经分配的数组空间,并且会引发查找性能的降低,好在这里根节点的每一个字符都不同,冲突发生的状况很是少。咱们看看词数目为427451的词典文件的冲突状况:算法

 

冲突次数为:1 的元素个数:2746
冲突次数为:2 的元素个数:1
冲突次数:2748
总槽数:12000
用槽数:9024
使用率:75.2%
剩槽数:2976

 

 

 



 


 

将词典文件和测试文本解压到当前目录下,使用下面的命令进行测试须要注意的是,这里的-Xmx参数指定的值是相应的词典实现所须要的最小的堆空间,若是再小就没法完成分词数组

 

nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV4 -Xmx40m  -cp target/word-1.0.jar org.apdplat.word.SegFile &
nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV3 -Xmx40m  -cp target/word-1.0.jar org.apdplat.word.SegFile &
nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV2 -Xmx40m  -cp target/word-1.0.jar org.apdplat.word.SegFile &
nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV1 -Xmx120m  -cp target/word-1.0.jar org.apdplat.word.SegFile &
nohup java -Ddic.class=org.apdplat.word.dictionary.impl.Trie -Xmx200m  -cp target/word-1.0.jar org.apdplat.word.SegFile &
nohup java -Ddic.class=org.apdplat.word.dictionary.impl.HashSet -Xmx50m  -cp target/word-1.0.jar org.apdplat.word.SegFile &

 

测试结果以下:性能



 



 



 


 

 

代码托管于GITHUB测试

 

参考资料:优化

一、中文分词十年回顾spa

二、中文信息处理中的分词问题code

三、汉语自动分词词典机制的实验研究

四、由字构词_中文分词新方法

五、汉语自动分词研究评述

 

NUTCH/HADOOP视频教程

相关文章
相关标签/搜索