zoukankan      html  css  js  c++  java
  • Trie树分词

    http://www.hankcs.com/program/java/tire-tree-participle.html

    最近在看Ansj中文分词的源码,以前没有涉足过这个领域,所以需要做一些笔记。

    Trie树

    首先是Ansj分词最基本的数据结构——Trie树。Trie树也称字典树,能在常数时间O(len)内实现插入和查询操作,是一种以空间换取时间的数据结构,广泛用于词频统计和输入统计领域。

    Ansj作者ansjsun为此数据结构专门开了一个项目,clone下来之后可以用作者提供的一个demo进行测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    package com.hankcs;
     
    import love.cq.domain.Forest;
    import love.cq.library.Library;
    import love.cq.splitWord.GetWord;
     
    import java.io.BufferedReader;
    import java.io.StringReader;
     
    /**
     * @author hankcs
     */
    public class Main
    {
        public static void main(String[] args) throws Exception
        {
    /**
     * 词典的构造.一行一个词后面是参数.可以从文件读取.可以是read流.
     */
            String dic =
                    "中国 1 zg " +
                    "人名 2 " +
                    "中国人民 4 " +
                    "人民 3 " +
                    "孙健 5 " +
                    "CSDN 6 " +
                    "java 7 " +
                    "java学习 10 ";
            Forest forest = Library.makeForest(new BufferedReader(new StringReader(dic)));
     
            /**
             * 删除一个单词
             */
            Library.removeWord(forest, "中国");
            /**
             * 增加一个新词
             */
            Library.insertWord(forest, "中国人");
            String content = "中国人名识别是中国人民的一个骄傲.孙健人民在CSDN中学到了很多最早iteye是java学习笔记叫javaeye但是java123只是一部分";
            GetWord udg = forest.getWord(content);
     
            String temp = null;
            while ((temp = udg.getFrontWords()) != null)
                System.out.println(temp + " " + udg.getParam(1) + " " + udg.getParam(2));
        }
    }

    输出:

    1
    2
    3
    4
    5
    6
    7
    中国人     null        null
    中国人民        null        null
    孙健      null        null
    人民      null        null
    CSDN        null        null
    java学习      null        null
    java        null        null

    这段demo的目的是利用一个小词典对后面一句话进行分词,词典被用来构造了一颗Trie树,也就是代码中的forest。

    词典每一行第一列是单词,之后的几列都是param(属性)。

    在tree_split中,一棵Trie树有四种不同的节点:

    • 根节点,上图的绿色节点。被称为Forest,没有实际含义,也不含属性。

    • 起始节点,上图的蓝色节点。是一个单词的开头第一个字,不含属性。

    • 中继节点,上图的黄色节点。可能是一个单词的结尾,含属性;也可能是另一个更长的单词的中间某个字,不含属性。

    • 结束节点,上图的红色节点。是一个单词的结尾,含属性。

    根节点使用Forest描述,而其它三种节点统一使用Branch描述,并用status = 1 2 3 来区分,它们有如下的类图关系:

    Root在构造的时候开了212个空槽以供放置子节点,每个汉字和其他字符都落在这个范围内。每次查找直接用汉字作为下标即可定位,Branch则使用动态数组分配内存,使用二分查找定位,这是Trie树的高速秘诀。Trie树的查询和插入都是类似的方法:从根节点开始沿着词语的开头字符走到结尾字符。在这里除了完成基本的维护操作,还需维护Branch的status。

    删除操作比较讨巧,统一将要删除的单词最后一个字对应的节点设为“起始节点”,那么它就不能构成这个词了。

    词典分词

    词典分词是一种实现简便、速度快但是错误率高的分词方式。用Trie树词典分词就是按照句子的字符顺序从root往下走,每走到一个结束节点则分出一个词。中途遇到的中继节点统统忽略,这种方式也称“最长匹配”,是一种很武断的方式。比如下面这个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    package com.hankcs;
     
    import love.cq.domain.Forest;
    import love.cq.library.Library;
    import love.cq.splitWord.GetWord;
     
    import java.io.BufferedReader;
    import java.io.StringReader;
     
    /**
     * @author hankcs
     */
    public class Main
    {
        public static void main(String[] args) throws Exception
        {
    /**
     * 词典的构造.一行一个词后面是参数.可以从文件读取.可以是read流.
     */
            String dic =
                    "商品 1 zg " +
                    "和服 2 " +
                    "服务 4 " ;
            Forest forest = Library.makeForest(new BufferedReader(new StringReader(dic)));
     
            String content = "商品和服务";
            GetWord udg = forest.getWord(content);
     
            String temp = null;
            while ((temp = udg.getFrontWords()) != null)
                System.out.println(temp + " " + udg.getParam(1) + " " + udg.getParam(2));
        }
    }

    输出:

    1
    2
    商品      zg      null
    和服      null        null

    很明显,效果不好。

    要想提高分词效果,就必须引入条件概率(隐马尔可夫模型),这就是Ansj分词的使命吧。

  • 相关阅读:
    error occurred during initialization of vm
    Service Discovery protocol(SDP)
    nRF51822EK_PRO
    Binder
    android samsung note3  device not found
    BLE pairing vs. bonding
    remote link Centos6.6 Horrible Slow
    depmod -a
    start and end call use itelephony and how to pick up a call
    WebService
  • 原文地址:https://www.cnblogs.com/DjangoBlog/p/4072966.html
Copyright © 2011-2022 走看看