HanLP用户自定义词典源码分析

1. 官方文档及参考链接

2. 源码解析

分析 com.hankcs.demo包下的DemoCustomDictionary.java 基于自定义词典使用标准分词HanLP.segment(text)的大致流程(HanLP版本1.5.3)。首先把自定义词添加到词库中:

CustomDictionary.add("攻城狮");
CustomDictionary.insert("白富美", "nz 1024");//指定了自定义词的词性和词频
CustomDictionary.add("单身狗", "nz 1024 n 1")//一个词可以有多个词性

添加词库的过程包括:

  • 若启用了归一化HanLP.Config.Normalization = true;,则会将自定义词进行归一化操作。归一化操作是基于词典文件 CharTable.txt 进行的。

  • 判断自定义词是否存在于自定义核心词典中

      public static boolean add(String word)
{
if (HanLP.Config.Normalization) word = CharTable.convert(word);
if (contains(word)) return false;//判断DoubleArrayTrie和BinTrie是否已经存在word
return insert(word, null);
}

  • 当自定义词不在词典中时,构造一个CoreDictionary.Attribute对象,若添加的自定义词未指定词性和词频,则词性默认为 nz,频次为1。然后试图使用DAT树将该 Attribute对象添加到核心词典中,由于自定义的词未存在于核心词典中,因为会添加失败,从而将自定义词放入到BinTrie中。因此,不在核心自定义词典中的词(动态增删的那些词语)是使用BinTrie树保存的。
      public static boolean insert(String word, String natureWithFrequency)
{
if (word == null) return false;
if (HanLP.Config.Normalization) word = CharTable.convert(word);
CoreDictionary.Attribute att = natureWithFrequency == null ? new CoreDictionary.Attribute(Nature.nz, 1) : CoreDictionary.Attribute.create(natureWithFrequency);
if (att == null) return false;
if (dat.set(word, att)) return true;
//"攻城狮"是动态加入的词语. 在核心词典中未匹配到,在自定义词典中也未匹配到, 动态增删的词语使用BinTrie保存
if (trie == null) trie = new BinTrie<CoreDictionary.Attribute>();
trie.put(word, att);
return true;
}

将自定义添加到BinTrie树后,接下来是使用分词算法分词了。假设使用的标准分词(viterbi算法来分词):

List<Vertex> vertexList = viterbi(wordNetAll);

分词具体过程可参考:

分词完成之后,返回的是一个 Vertex 列表。如下图所示:

然后根据 是否开启用户自定义词典 配置来决定将分词结果与用户添加的自定义词进行合并。默认情况下,config.useCustomDictionary是true,即开启用户自定义词典。

        if (config.useCustomDictionary)
{
if (config.indexMode > 0)
combineByCustomDictionary(vertexList, wordNetAll);
else combineByCustomDictionary(vertexList);
}

combineByCustomDictionary(vertexList)由两个过程组成:

  • 合并DAT 树中的用户自定义词。这些词是从 词典配置文件 CustomDictionary.txt 中加载得到的。

  • 合并BinTrie 树中的用户自定义词。这些词是 代码中动态添加的:CustomDictionary.add("攻城狮")

  //DAT合并
DoubleArrayTrie<CoreDictionary.Attribute> dat = CustomDictionary.dat;
....
// BinTrie合并
if (CustomDictionary.trie != null)//用户通过CustomDictionary.add("攻城狮"); 动态增加了词典
{
....

合并之后的结果如下:

3. 关于用户自定义词典

总结一下,开启自定义分词的流程基本如下:

  • HanLP启动时加载词典文件中的CustomDictionary.txt 到DoubleArrayTrie中;用户通过 CustomDictionary.add("攻城狮");将自定义词添加到BinTrie中。
  • 使用某一种分词算法分词
  • 将分词结果与DoubleArrayTrie或BinTrie中的自定义词进行合并,最终返回输出结果

HanLP作者在HanLP issue783:上面说:词典不等于分词、分词不等于自然语言处理;推荐使用语料而不是词典去修正统计模型。由于分词算法不能将一些“特定领域”的句子分词正确,于是为了纠正分词结果,把想要的分词结果添加到自定义词库中,但最好使用语料来纠正分词的结果。另外,作者还说了在以后版本中不保证继续支持动态添加自定义词典。以上是阅读源码过程中的一些粗浅理解,仅供参考。

原文:http://www.cnblogs.com/hapjin/p/8992280.html

HanLP用户自定义词典源码分析的更多相关文章

  1. HanLP用户自定义词典源码分析详解

    1. 官方文档及参考链接 l 关于词典问题Issue,首先参考:FAQ l 自定义词典其实是基于规则的分词,它的用法参考这个issue l 如果有些数量词.字母词需要分词,可参考:P2P和C2C这种词 ...

  2. [源码分析] 分布式任务队列 Celery 之 发送Task & AMQP

    [源码分析] 分布式任务队列 Celery 之 发送Task & AMQP 目录 [源码分析] 分布式任务队列 Celery 之 发送Task & AMQP 0x00 摘要 0x01 ...

  3. 深入理解 spring 容器,源码分析加载过程

    Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC ...

  4. 【集合框架】JDK1.8源码分析之TreeMap(五)

    一.前言 当我们需要把插入的元素进行排序的时候,就是时候考虑TreeMap了,从名字上来看,TreeMap肯定是和树是脱不了干系的,它是一个排序了的Map,下面我们来着重分析其源码,理解其底层如何实现 ...

  5. 【JUC】JDK1.8源码分析之ThreadPoolExecutor(一)

    一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...

  6. 【Pig源码分析】谈谈Pig的数据模型

    1. 数据模型 Schema Pig Latin表达式操作的是relation,FILTER.FOREACH.GROUP.SPLIT等关系操作符所操作的relation就是bag,bag为tuple的 ...

  7. Struts2 源码分析——过滤器(Filter)

    章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...

  8. Orchard源码分析(1):Orchard架构

      本文主要参考官方文档"How Orchard works"以及Orchardch上的翻译.   源码分析应该做到庖丁解牛,而不是以管窥豹或瞎子摸象.所以先对Orchard架构有 ...

  9. Mahout源码分析之 -- 文档向量化TF-IDF

    fesh个人实践,欢迎经验交流!Blog地址:http://www.cnblogs.com/fesh/p/3775429.html Mahout之SparseVectorsFromSequenceFi ...

随机推荐

  1. JAVA 获取指定网址的IP地址 实例

    如今买票是一大难事,在高峰时段 打开12306网站,慢的像蜗牛,想到以前用修改hosts文件来登录Google(Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址 ...

  2. [模板]KMP算法

    昨天晚上一直在调KMP(模板传送门),因为先学了hash[关于hash的内容会在随后进行更(gu)新(gu)]于是想从1开始读...结果写出来之后一直死循环,最后我还是改回从0读入字符串了. [预先定 ...

  3. 「JLOI2015」骗我呢 解题报告?

    「JLOI2015」骗我呢 这什么神仙题 \[\color{purple}{Link}\] 可以学到的东西 对越过直线的东西翻折进行容斥 之类的..吧? Code: #include <cstd ...

  4. python列表转字符串

    temp = "".join(sorted(arr[i])) arr[i] = temp

  5. This license xxx has been cancelled 解决

    上节回顾:JetBrains全家桶破解思路 hosts屏蔽一下即可,Linux是:/etc/hosts 0.0.0.0 account.jetbrains.com 重新输入Code即可,最后补一个地址 ...

  6. bzoj3238 差异

    题目链接 思路 观察题目中的式子,可以发现前两项是定值.所以只需要求出最后一项就行了. 然后题目就转化为了求字符串中所有后缀的\(lcp\)长度之和. 可以想到用后缀数组.在后缀数组上两个后缀的\(l ...

  7. Django 跨域请求

    跨域:通过js或python在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(Django)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  8. Command `bundle` unrecognized. Make sure that you have run `npm install` and that you are inside a react-native project.

    呃呃,在写下面的代码时出现的问题,解决办法是npm install或者yarn,如果yarn报错,再npm install就可以了 下面的是携程App首页的样式,有轮播,我没有实现出来 代码如下: / ...

  9. R: 修改镜像、bioconductor安装及go基因富集分析

    1.安装bioconductor及go分析涉及的相关包 source("http://bioconductor.org/biocLite.R") options(BioC_mirr ...

  10. Day22 常用模块01

    1. collections模块collections模块主要封装了⼀些关于集合类的相关操作. 比如, 我们学过的Iterable,Iterator等等. 除了这些以外, collections还提供 ...