放牧代码和思想
专注自然语言处理、机器学习算法
    恕不接待索要源码语料者、索求技术方案者、以及不Google的懒人。

HanLP自然语言处理包开源

目录

支持中文分词(N-最短路分词、CRF分词、索引分词、用户自定义词典、词性标注),命名实体识别(中国人名、音译人名、日本人名、地名、实体机构名识别),关键词提取,自动摘要,短语提取,拼音转换,简繁转换,文本推荐,依存句法分析(MaxEnt依存句法分析、CRF依存句法分析)。提供Lucene插件,兼容Lucene4.x。

HanLP: Han Language Processing Fork HanLP 给HanLP点赞 关注HanLP

汉语言处理包

欢迎 fork HanLP! 为HanLP加star是最好的支持!  Maven仓库最新版 


HanLP是由一系列模型与算法组成的Java工具包,目标是促进自然语言处理在生产环境中的应用。HanLP具备功能完善、性能高效、架构清晰、语料时新、可自定义的特点。

HanLP提供下列功能:

  • 中文分词

    • 最短路分词

    • N-最短路分词

    • CRF分词

    • 索引分词

    • 极速词典分词

    • 用户自定义词典

  • 词性标注

  • 命名实体识别

    • 中国人名识别

    • 音译人名识别

    • 日本人名识别

    • 地名识别

    • 实体机构名识别

  • 关键词提取

    • TextRank关键词提取

  • 自动摘要

    • TextRank自动摘要

  • 短语提取

    • 基于互信息和左右信息熵的短语提取

  • 拼音转换

    • 多音字

    • 声母

    • 韵母

    • 声调

  • 简繁转换

    • 繁体中文分词

    • 简繁分歧词

  • 文本推荐

    • 语义推荐

    • 拼音推荐

    • 字词推荐

  • 依存句法分析

    • 基于神经网络的高性能依存句法分析器

    • MaxEnt依存句法分析

    • CRF依存句法分析

  • 语料库工具

    • 分词语料预处理

    • 词频词性词典制作

    • BiGram统计

    • 词共现统计

    • CoNLL语料预处理

    • CoNLL UA/LA/DA评测工具

在提供丰富功能的同时,HanLP内部模块坚持低耦合、模型坚持惰性加载、服务坚持静态提供、词典坚持明文发布,使用非常方便,同时自带一些语料处理工具,帮助用户训练自己的语料。


项目地址

HanLP项目主页:https://github.com/hankcs/HanLP Fork HanLP 给HanLP点赞 关注HanLP

HanLP下载地址:https://github.com/hankcs/HanLP/releases 

最新binary、文档都项目主页为准。博客是一个相对容易编辑的地方,国内访问速度较快,所以用做文档备份。

技术问题请在Github上发issue ,大家一起讨论,也方便集中管理。博客留言、微博私信不受理任何HanLP相关的问题,谢谢合作!

反馈问题的时候请一定附上版本号触发代码、输入输出否则无法处理

内存要求

内存120MB以上(-Xms120m -Xmx120m -Xmn64m),标准数据包(35万核心词库+默认用户词典),分词测试正常。

全部词典和模型都是惰性加载的,如果你只用拼音转换的话,则只加载拼音词典,未加载的词典相当于不存在,不占内存。同理,模型也是如此。

更新日志

最新版请移步GitHub

旧版本一览——

2015年7月12日 发布了1.2.4版。在长时间的思考后,决定将用户词典用于分词后的合并处理,使得用户词典中的长词更容易切分出来。

2015年5月11日 发布了1.2.2。主要支持了并行化,优化了CRF分词,新增了TnT分词器,支持了数量词识别。数据包data-for-1.2.2.zip也做了小幅调整。其实最新的更新日志都可以在GitHub上看到,比博客详细多了,更新也勤快多了。

2015年5月02日 发布了1.1.5版。主要将ACDAT降级为DAT,内存占用减少了一半。所以需要删缓存重新构建,或者下载data-for-1.1.5.zip。另外,还发布了内置数据包的Portable版,可以通过maven直接引入,零配置!

2015年4月28日 发布了1.1.4版。这次训练了一个新的CRF分词模型,感觉效果要好很多(注:该模型与旧版本不兼容)。诸位可以评估一下,提出宝贵意见。


下载与配置

方式一、通过Maven的pom.xml

Maven仓库最新版

为了方便用户,特提供内置了数据包的Portable版,只需在pom.xml加入:

<dependency>
    <groupId>com.hankcs</groupId>
    <artifactId>hanlp</artifactId>
    <version>portable-1.2.4</version>
</dependency>

零配置,即可使用基本功能(除CRF分词、依存句法分析外的全部功能)。连Maven都懒得用的话,可以直接下载portable版的jar

如果用户有自定义的需求,可以参考方式二,使用hanlp.properties进行配置。

目前Portable体积仅仅5.7MB,作为代价,使用的是1998年的小词典,对现代汉语的支持有限;所以还是建议外挂下面的数据包比较好。

方式二、下载jar、data、hanlp.properties

HanLP将数据与程序分离,给予用户自定义的自由。

1、下载jar

hanlp.jar

2、下载data

数据包 功能 体积(MB)
data.zip 全部词典,全部模型 280(注:分词词典大约40MB,主要是句法分析模型占体积,可以自行删除。)

GitHub的release页面Ctrl+F搜索data即可,下载后解压到任意目录,接下来通过配置文件告诉HanLP数据包的位置。

HanLP中的数据分为词典模型,其中词典是词法分析必需的,模型是句法分析必需的。

data
│  
├─dictionary
└─model

用户可以自行增删替换,如果不需要句法分析功能的话,随时可以删除model文件夹。

3、配置文件

示例配置文件:hanlp.properties

配置文件的作用是告诉HanLP数据包的位置,只需修改第一行

root=usr/home/HanLP/

为data的父目录即可,比如data目录是/Users/hankcs/Documents/data,那么root=/Users/hankcs/Documents/

  • 如果选用mini词典的话,则需要修改配置文件:
    CoreDictionaryPath=data/dictionary/CoreNatureDictionary.mini.txt
    BiGramDictionaryPath=data/dictionary/CoreNatureDictionary.ngram.mini.txt

最后将HanLP.properties放入classpath即可,对于任何项目,都可以放到src目录或resources目录下,编译时IDE会自动将其复制到classpath中。

如果放置不当,HanLP会智能提示当前环境下的合适路径,并且尝试从项目根目录读取数据集。

调用方法

HanLP几乎所有的功能都可以通过工具类HanLP快捷调用,当你想不起来调用方法时,只需键入HanLP.,IDE应当会给出提示,并展示HanLP完善的文档。

推荐用户始终通过工具类HanLP调用,这么做的好处是,将来HanLP升级后,用户无需修改调用代码。

所有Demo都位于com.hankcs.demo下。

1. 第一个Demo

System.out.println(HanLP.segment("你好,欢迎使用HanLP汉语处理包!"));

2. 标准分词

List<Term> termList = StandardTokenizer.segment("商品和服务");
System.out.println(termList);
  • 说明

    • HanLP中有一系列“开箱即用”的静态分词器,以Tokenizer结尾,在接下来的例子中会继续介绍。

    • HanLP.segment其实是对StandardTokenizer.segment的包装。

    • 分词结果包含词性,每个词性的意思请查阅《HanLP词性标注集》

  • 算法详解

3. NLP分词

List<Term> termList = NLPTokenizer.segment("中国科学院计算技术研究所的宗成庆教授正在教授自然语言处理课程");
System.out.println(termList);
  • 说明

    • NLP分词NLPTokenizer会执行全部命名实体识别和词性标注。

4. 索引分词

List<Term> termList = IndexTokenizer.segment("主副食品");
for (Term term : termList)
{
    System.out.println(term + " [" + term.offset + ":" + (term.offset + term.word.length()) + "]");
}
  • 说明

    • 索引分词IndexTokenizer是面向搜索引擎的分词器,能够对长词全切分,另外通过term.offset可以获取单词在文本中的偏移量。

5. N-最短路径分词

Segment nShortSegment = new NShortSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
Segment shortestSegment = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
String[] testCase = new String[]{
        "今天,刘志军案的关键人物,山西女商人丁书苗在市二中院出庭受审。",
        "刘喜杰石国祥会见吴亚琴先进事迹报告团成员",
        };
for (String sentence : testCase)
{
    System.out.println("N-最短分词:" + nShortSegment.seg(sentence) + "\n最短路分词:" + shortestSegment.seg(sentence));
}
  • 说明

    • N最短路分词器NShortSegment比最短路分词器慢,但是效果稍微好一些,对命名实体识别能力更强。

    • 一般场景下最短路分词的精度已经足够,而且速度比N最短路分词器快几倍,请酌情选择。

  • 算法详解

6. CRF分词

/**
 * CRF分词(在最新训练的未压缩100MB模型下,能够取得较好的效果,可以投入生产环境)
 *
 * @author hankcs
 */
public class DemoCRFSegment
{
    public static void main(String[] args)
    {
        HanLP.Config.ShowTermNature = false;    // 关闭词性显示
        Segment segment = new CRFSegment();
        String[] sentenceArray = new String[]
                {
                        "HanLP是由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用。",
                        "鐵桿部隊憤怒情緒集結 馬英九腹背受敵",           // 繁体无压力
                        "馬英九回應連勝文“丐幫說”:稱黨內同志談話應謹慎",
                        "高锰酸钾,强氧化剂,紫红色晶体,可溶于水,遇乙醇即被还原。常用作消毒剂、水净化剂、氧化剂、漂白剂、毒气吸收剂、二氧化碳精制剂等。", // 专业名词有一定辨识能力
                        "《夜晚的骰子》通过描述浅草的舞女在暗夜中扔骰子的情景,寄托了作者对庶民生活区的情感",    // 非新闻语料
                        "这个像是真的[委屈]前面那个打扮太江户了,一点不上品...@hankcs",                       // 微博
                        "鼎泰丰的小笼一点味道也没有...每样都淡淡的...淡淡的,哪有食堂2A的好次",
                        "克里斯蒂娜·克罗尔说:不,我不是虎妈。我全家都热爱音乐,我也鼓励他们这么做。",
                        "今日APPS:Sago Mini Toolbox培养孩子动手能力",
                        "财政部副部长王保安调任国家统计局党组书记",
                        "2.34米男子娶1.53米女粉丝 称夫妻生活没问题",
                        "你看过穆赫兰道吗",
                        "乐视超级手机能否承载贾布斯的生态梦"
                };
        for (String sentence : sentenceArray)
        {
            List<Term> termList = segment.seg(sentence);
            System.out.println(termList);
        }
    }
}

7. 极速词典分词

/**
 * 演示极速分词,基于AhoCorasickDoubleArrayTrie实现的词典分词,适用于“高吞吐量”“精度一般”的场合
 * @author hankcs
 */
public class DemoHighSpeedSegment
{
    public static void main(String[] args)
    {
        String text = "江西鄱阳湖干枯,中国最大淡水湖变成大草原";
        System.out.println(SpeedTokenizer.segment(text));
        long start = System.currentTimeMillis();
        int pressure = 1000000;
        for (int i = 0; i < pressure; ++i)
        {
            SpeedTokenizer.segment(text);
        }
        double costTime = (System.currentTimeMillis() - start) / (double)1000;
        System.out.printf("分词速度:%.2f字每秒", text.length() * pressure / costTime);
    }
}

8. 用户自定义词典

public class DemoCustomDictionary
{
    public static void main(String[] args)
    {
        // 动态增加
        CustomDictionary.add("攻城狮");
        // 强行插入
        CustomDictionary.insert("白富美", "nz 1024");
        // 删除词语(注释掉试试)
//        CustomDictionary.remove("攻城狮");
        System.out.println(CustomDictionary.add("单身狗", "nz 1024 n 1"));
        System.out.println(CustomDictionary.get("单身狗"));

        String text = "攻城狮逆袭单身狗,迎娶白富美,走上人生巅峰";  // 怎么可能噗哈哈!

        // DoubleArrayTrie分词
        final char[] charArray = text.toCharArray();
        CustomDictionary.parseText(charArray, new AhoCorasickDoubleArrayTrie.IHit<CoreDictionary.Attribute>()
        {
            @Override
            public void hit(int begin, int end, CoreDictionary.Attribute value)
            {
                System.out.printf("[%d:%d]=%s %s\n", begin, end, new String(charArray, begin, end - begin), value);
            }
        });
        // 首字哈希之后二分的trie树分词
        BaseSearcher searcher = CustomDictionary.getSearcher(text);
        Map.Entry entry;
        while ((entry = searcher.next()) != null)
        {
            System.out.println(entry);
        }

        // 标准分词
        System.out.println(HanLP.segment(text));

        // Note:动态增删不会影响词典文件
        // 目前CustomDictionary使用DAT储存词典文件中的词语,用BinTrie储存动态加入的词语,前者性能高,后者性能低
        // 之所以保留动态增删功能,一方面是历史遗留特性,另一方面是调试用;未来可能会去掉动态增删特性。
    }
  • 说明

    • CustomDictionary是一份全局的用户自定义词典,可以随时增删,影响全部分词器。

    • 另外可以在任何分词器中关闭它。通过代码动态增删不会保存到词典文件。

  • 追加词典

    • CustomDictionary主词典文本路径是data/dictionary/custom/CustomDictionary.txt,用户可以在此增加自己的词语(不推荐);也可以单独新建一个文本文件,通过配置文件CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; 我的词典.txt;来追加词典(推荐)。

    • 始终建议将相同词性的词语放到同一个词典文件里,便于维护和分享。

  • 词典格式

    • 每一行代表一个单词,格式遵从[单词] [词性A] [A的频次] [词性B] [B的频次] ... 如果不填词性则表示采用词典的默认词性。

    • 词典的默认词性默认是名词n,可以通过配置文件修改:全国地名大全.txt ns;如果词典路径后面空格紧接着词性,则该词典默认是该词性。

    • 关于用户词典的更多信息请参考词典说明一章。

  • 算法详解

9. 中国人名识别

String[] testCase = new String[]{
        "签约仪式前,秦光荣、李纪恒、仇和等一同会见了参加签约的企业家。",
        "王国强、高峰、汪洋、张朝阳光着头、韩寒、小四",
        "张浩和胡健康复员回家了",
        "王总和小丽结婚了",
        "编剧邵钧林和稽道青说",
        "这里有关天培的有关事迹",
        "龚学平等领导,邓颖超生前",
        };
Segment segment = HanLP.newSegment().enableNameRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}
  • 说明

    • 目前分词器基本上都默认开启了中国人名识别,比如HanLP.segment()接口中使用的分词器等等,用户不必手动开启;上面的代码只是为了强调。

    • 有一定的误命中率,比如误命中关键年,则可以通过在data/dictionary/person/nr.txt加入一条关键年 A 1来排除关键年作为人名的可能性,也可以将关键年作为新词登记到自定义词典中。

    • 如果你通过上述办法解决了问题,欢迎向我提交pull request,词典也是宝贵的财富。

  • 算法详解

10. 音译人名识别

String[] testCase = new String[]{
                "一桶冰水当头倒下,微软的比尔盖茨、Facebook的扎克伯格跟桑德博格、亚马逊的贝索斯、苹果的库克全都不惜湿身入镜,这些硅谷的科技人,飞蛾扑火似地牺牲演出,其实全为了慈善。",
                "世界上最长的姓名是简森·乔伊·亚历山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马尔尼·梅尔斯·帕特森·汤普森·华莱士·普雷斯顿。",
        };
Segment segment = HanLP.newSegment().enableTranslatedNameRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}

11. 日本人名识别

String[] testCase = new String[]{
        "北川景子参演了林诣彬导演的《速度与激情3》",
        "林志玲亮相网友:确定不是波多野结衣?",
};
Segment segment = HanLP.newSegment().enableJapaneseNameRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}

12. 地名识别

String[] testCase = new String[]{
        "武胜县新学乡政府大楼门前锣鼓喧天",
        "蓝翔给宁夏固原市彭阳县红河镇黑牛沟村捐赠了挖掘机",
};
Segment segment = HanLP.newSegment().enablePlaceRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}
  • 说明

    • 目前标准分词器都默认关闭了地名识别,用户需要手动开启;这是因为消耗性能,其实多数地名都收录在核心词典和用户自定义词典中。

    • 在生产环境中,能靠词典解决的问题就靠词典解决,这是最高效稳定的方法。

  • 算法详解

13. 机构名识别

String[] testCase = new String[]{
        "我在上海林原科技有限公司兼职工作,",
        "我经常在台川喜宴餐厅吃饭,",
        "偶尔去地中海影城看电影。",
};
Segment segment = HanLP.newSegment().enableOrganizationRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}
  • 说明

    • 目前分词器默认关闭了机构名识别,用户需要手动开启;这是因为消耗性能,其实常用机构名都收录在核心词典和用户自定义词典中。

    • HanLP的目的不是演示动态识别,在生产环境中,能靠词典解决的问题就靠词典解决,这是最高效稳定的方法。

  • 算法详解

14. 关键词提取

String content = "程序员(英文Programmer)是从事程序开发、维护的专业人员。一般将程序员分为程序设计人员和程序编码人员,但两者的界限并不非常清楚,特别是在中国。软件从业人员分为初级程序员、高级程序员、系统分析员和项目经理四大类。";
List<String> keywordList = HanLP.extractKeyword(content, 5);
System.out.println(keywordList);

15. 自动摘要

String document = "算法可大致分为基本算法、数据结构的算法、数论算法、计算几何的算法、图的算法、动态规划以及数值分析、加密算法、排序算法、检索算法、随机化算法、并行算法、厄米变形模型、随机森林算法。\n" +
        "算法可以宽泛的分为三类,\n" +
        "一,有限的确定性算法,这类算法在有限的一段时间内终止。他们可能要花很长时间来执行指定的任务,但仍将在一定的时间内终止。这类算法得出的结果常取决于输入值。\n" +
        "二,有限的非确定算法,这类算法在有限的时间内终止。然而,对于一个(或一些)给定的数值,算法的结果并不是唯一的或确定的。\n" +
        "三,无限的算法,是那些由于没有定义终止定义条件,或定义的条件无法由输入的数据满足而不终止运行的算法。通常,无限算法的产生是由于未能确定的定义终止条件。";
List<String> sentenceList = HanLP.extractSummary(document, 3);
System.out.println(sentenceList);

16. 短语提取

String text = "算法工程师\n" +
        "算法(Algorithm)是一系列解决问题的清晰指令,也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。" +
        "如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、" +
        "空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。算法工程师就是利用算法处理事物的人。\n" +
        "\n" +
        "1职位简介\n" +
        "算法工程师是一个非常高端的职位;\n" +
        "专业要求:计算机、电子、通信、数学等相关专业;\n" +
        "学历要求:本科及其以上的学历,大多数是硕士学历及其以上;\n" +
        "语言要求:英语要求是熟练,基本上能阅读国外专业书刊;\n" +
        "必须掌握计算机相关知识,熟练使用仿真工具MATLAB等,必须会一门编程语言。\n" +
        "\n" +
        "2研究方向\n" +
        "视频算法工程师、图像处理算法工程师、音频算法工程师 通信基带算法工程师\n" +
        "\n" +
        "3目前国内外状况\n" +
        "目前国内从事算法研究的工程师不少,但是高级算法工程师却很少,是一个非常紧缺的专业工程师。" +
        "算法工程师根据研究领域来分主要有音频/视频算法处理、图像技术方面的二维信息算法处理和通信物理层、" +
        "雷达信号处理、生物医学信号处理等领域的一维信息算法处理。\n" +
        "在计算机音视频和图形图像技术等二维信息算法处理方面目前比较先进的视频处理算法:机器视觉成为此类算法研究的核心;" +
        "另外还有2D转3D算法(2D-to-3D conversion),去隔行算法(de-interlacing),运动估计运动补偿算法" +
        "(Motion estimation/Motion Compensation),去噪算法(Noise Reduction),缩放算法(scaling)," +
        "锐化处理算法(Sharpness),超分辨率算法(Super Resolution),手势识别(gesture recognition),人脸识别(face recognition)。\n" +
        "在通信物理层等一维信息领域目前常用的算法:无线领域的RRM、RTT,传送领域的调制解调、信道均衡、信号检测、网络优化、信号分解等。\n" +
        "另外数据挖掘、互联网搜索算法也成为当今的热门方向。\n" +
        "算法工程师逐渐往人工智能方向发展。";
List<String> phraseList = HanLP.extractPhrase(text, 5);
System.out.println(phraseList);

17. 拼音转换

/**
 * 汉字转拼音
 * @author hankcs
 */
public class DemoPinyin
{
    public static void main(String[] args)
    {
        String text = "重载不是重任";
        List<Pinyin> pinyinList = HanLP.convertToPinyinList(text);
        System.out.print("原文,");
        for (char c : text.toCharArray())
        {
            System.out.printf("%c,", c);
        }
        System.out.println();
        System.out.print("拼音(数字音调),");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin);
        }
        System.out.println();
        System.out.print("拼音(符号音调),");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getPinyinWithToneMark());
        }
        System.out.println();
        System.out.print("拼音(无音调),");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getPinyinWithoutTone());
        }
        System.out.println();
        System.out.print("声调,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getTone());
        }
        System.out.println();
        System.out.print("声母,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getShengmu());
        }
        System.out.println();
        System.out.print("韵母,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getYunmu());
        }
        System.out.println();
        System.out.print("输入法头,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getHead());
        }
        System.out.println();
    }
}
  • 说明

    • HanLP不仅支持基础的汉字转拼音,还支持声母、韵母、音调、音标和输入法首字母首声母功能。

    • HanLP能够识别多音字,也能给繁体中文注拼音。

    • 最重要的是,HanLP采用的模式匹配升级到AhoCorasickDoubleArrayTrie,性能大幅提升,能够提供毫秒级的响应速度!

  • 算法详解

18. 简繁转换

/**
 * 简繁转换
 * @author hankcs
 */
public class DemoTraditionalChinese2SimplifiedChinese
{
    public static void main(String[] args)
    {
        System.out.println(HanLP.convertToTraditionalChinese("用笔记本电脑写程序"));
        System.out.println(HanLP.convertToSimplifiedChinese("「以後等妳當上皇后,就能買士多啤梨慶祝了」"));
    }
}

19. 文本推荐

/**
 * 文本推荐(句子级别,从一系列句子中挑出与输入句子最相似的那一个)
 * @author hankcs
 */
public class DemoSuggester
{
    public static void main(String[] args)
    {
        Suggester suggester = new Suggester();
        String[] titleArray =
        (
                "威廉王子发表演说 呼吁保护野生动物\n" +
                "《时代》年度人物最终入围名单出炉 普京马云入选\n" +
                "“黑格比”横扫菲:菲吸取“海燕”经验及早疏散\n" +
                "日本保密法将正式生效 日媒指其损害国民知情权\n" +
                "英报告说空气污染带来“公共健康危机”"
        ).split("\\n");
        for (String title : titleArray)
        {
            suggester.addSentence(title);
        }
        System.out.println(suggester.suggest("发言", 1));       // 语义
        System.out.println(suggester.suggest("危机公共", 1));   // 字符
        System.out.println(suggester.suggest("mayun", 1));      // 拼音
    }
}
  • 说明

    • 在搜索引擎的输入框中,用户输入一个词,搜索引擎会联想出最合适的搜索词,HanLP实现了类似的功能。

    • 可以动态调节每种识别器的权重

20. 语义距离

/**
 * 语义距离
 * @author hankcs
 */
public class DemoWordDistance
{
    public static void main(String[] args)
    {
        String[] wordArray = new String[]
                {
                        "香蕉",
                        "苹果",
                        "白菜",
                        "水果",
                        "蔬菜",
                        "自行车",
                        "公交车",
                        "飞机",
                        "买",
                        "卖",
                        "购入",
                        "新年",
                        "春节",
                        "丢失",
                        "补办",
                        "办理",
                        "送给",
                        "寻找",
                        "孩子",
                        "教室",
                        "教师",
                        "会计",
                };
        for (String a : wordArray)
        {
            for (String b : wordArray)
            {
                System.out.println(a + "\t" + b + "\t之间的距离是\t" + CoreSynonymDictionary.distance(a, b));
            }
        }
    }
}
  • 说明

    • 设想的应用场景是搜索引擎对词义的理解,词与词并不只存在“同义词”与“非同义词”的关系,就算是同义词,它们之间的意义也是有微妙的差别的。

  • 算法

    • 为每个词分配一个语义ID,词与词的距离通过语义ID的差得到。语义ID通过《同义词词林扩展版》计算而来。

21. 依存句法解析

/**
 * 依存句法分析(神经网络句法模型需要-Xms1g -Xmx1g -Xmn512m)
 * @author hankcs
 */
public class DemoDependencyParser
{
    public static void main(String[] args)
    {
        CoNLLSentence sentence = HanLP.parseDependency("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。");
        System.out.println(sentence);
        // 可以方便地遍历它
        for (CoNLLWord word : sentence)
        {
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 也可以直接拿到数组,任意顺序或逆序遍历
        CoNLLWord[] wordArray = sentence.getWordArray();
        for (int i = wordArray.length - 1; i >= 0; i--)
        {
            CoNLLWord word = wordArray[i];
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 还可以直接遍历子树,从某棵子树的某个节点一路遍历到虚根
        CoNLLWord head = wordArray[12];
        while ((head = head.HEAD) != null)
        {
            if (head == CoNLLWord.ROOT) System.out.println(head.LEMMA);
            else System.out.printf("%s --(%s)--> ", head.LEMMA, head.DEPREL);
        }
    }
}

词典说明

本章详细介绍HanLP中的词典格式,满足用户自定义的需要。HanLP中有许多词典,它们的格式都是相似的,形式都是文本文档,随时可以修改。

基本格式

词典分为词频词性词典和词频词典。

  • 词频词性词典

    • 每一行代表一个单词,格式遵从[单词] [词性A] [A的频次] [词性B] [B的频次] ...

  • 词频词典

    • 每一行代表一个单词,格式遵从[单词] [单词的频次]

    • 每一行的分隔符为空格符或制表符

少数词典有自己的专用格式,比如同义词词典兼容《同义词词林扩展版》的文本格式,而转移矩阵词典则是一个csv表格。

下文主要介绍通用词典,如不注明,词典特指通用词典。

数据结构

Trie树(字典树)是HanLP中使用最多的数据结构,为此,我实现了通用的Trie树,支持泛型、遍历、储存、载入。

用户自定义词典采用AhoCorasickDoubleArrayTrie和二分Trie树储存,其他词典采用基于双数组Trie树(DoubleArrayTrie)实现的AC自动机AhoCorasickDoubleArrayTrie

储存形式

词典有两个形态:文本文件(filename.txt)和缓存文件(filename.txt.bin或filename.txt.trie.dat和filename.txt.trie.value)。

  • 文本文件  

    • 采用明文储存,UTF-8编码,CRLF换行符。

  • 缓存文件

    • 就是一些二进制文件,通常在文本文件的文件名后面加上.bin表示。有时候是.trie.dat和.trie.value。后者是历史遗留产物,分别代表trie树的数组和值。

    • 如果你修改了任何词典,只有删除缓存才能生效。

修改方法

HanLP的核心词典训练自人民日报2014语料,语料不是完美的,总会存在一些错误。这些错误可能会导致分词出现奇怪的结果,这时请打开调试模式排查问题:

HanLP.Config.enableDebug();
  • 核心词性词频词典

    • 比如你在data/dictionary/CoreNatureDictionary.txt中发现了一个不是词的词,或者词性标注得明显不对,那么你可以修改它,然后删除缓存文件使其生效。

  • 核心二元文法词典

    • 二元文法词典data/dictionary/CoreNatureDictionary.ngram.txt储存的是两个词的接续,如果你发现不可能存在这种接续时,删掉即可。

    • 你也可以添加你认为合理的接续,但是这两个词必须同时在核心词典中才会生效。

  • 命名实体识别词典

    • 基于角色标注的命名实体识别比较依赖词典,所以词典的质量大幅影响识别质量。

    • 这些词典的格式与原理都是类似的,请阅读相应的文章或代码修改它。

如果问题解决了,欢迎向我提交一个pull request,这是我在代码库中保留明文词典的原因,众人拾柴火焰高!


版权

Apache License Version 2.0

  • Apache License Version 2.0

  • HanLP产品初始知识产权归上海林原信息科技有限公司所有,任何人和企业可以无偿使用,可以对产品、源代码进行任何形式的修改,可以打包在其他产品中进行销售。

  • 任何使用了HanLP的全部或部分功能、词典、模型的项目、产品或文章等形式的成果必须显式注明HanLP及此项目主页。

鸣谢

感谢下列优秀开源项目:

感谢NLP界各位学者老师的著作:

  • 《基于角色标注的中国人名自动识别研究》张华平 刘群

  • 《基于层叠隐马尔可夫模型的中文命名实体识别》俞鸿魁 张华平 刘群 吕学强 施水才

  • 《基于角色标注的中文机构名识别》俞鸿魁 张华平 刘群

  • 《基于最大熵的依存句法分析》 辛霄 范士喜 王轩 王晓龙

  • An Efficient Implementation of Trie Structures, JUN-ICHI AOE AND KATSUSHI MORIMOTO

  • TextRank: Bringing Order into Texts, Rada Mihalcea and Paul Tarau

感谢上海林原信息科技有限公司的刘先生,允许我利用工作时间开发HanLP,提供服务器和域名,并且促成了开源。感谢诸位用户的关注和使用,HanLP并不完善,未来还恳求各位NLP爱好者多多关照,提出宝贵意见。 

作者 @hankcs  Follow Hankcs

2014年12月16日

转载须注明:码农场 » HanLP自然语言处理包开源

分享到:更多 ()
  1. 请教一下一些使用上的问题,不知道是否适合在github提问,就在此发言了,恳请解答,谢谢。
    1. 扩展辞典的部分,由于业务上的需要,需要新增词性,例如要辨识颜色词,我在com.hankcs.hanlp.corpus.tag.Nature 新增了词性 color。
    然后发现如果扩展词库与核心词库冲突,会以核心词库的词性优先,该如何修改呢?

    2.SpeedTokenizer 使用 AhoCorasickDoubleArrayTrie 速度极快,对于英文与数字 也会全切分
    能指点一下该如何修该成 与CustomDictionary 一样的切分方式吗? 例如 apple 120克 切为 apple 120 克 ,而不是 a p p l e 1 2 0 克

    • 1、com/hankcs/hanlp/dictionary/CustomDictionary.java的147行去掉加载期间排重判断,com/hankcs/hanlp/seg/Other/AhoCorasickSegment.java的64行改成大于等于(或者交换两个parseText的顺序)就可以以自定义词典优先
      2、checkout最新代码,然后SpeedTokenizer.SEGMENT.enablePartOfSpeechTagging(true);就行了

      • 您好,我发现程序里面有一个bug,我在分词的时候。如下一句话,会报出错误“ 嗷嗷嗷嗷~正好防晒霜快完啦快接上嗷嗷嗷嗷~人民的好伙伴啊嗷嗷嗷~”

        • 你好,1.2.4版中没有问题:
          String text = "嗷嗷嗷嗷~正好防晒霜快完啦快接上嗷嗷嗷嗷~人民的好伙伴啊嗷嗷嗷~";
          System.out.println(HanLP.segment(text));
          输出:
          [嗷嗷/o, 嗷嗷/o, ~/nx, 正好/z, 防晒霜/n, 快/a, 完/v, 啦/y, 快/a, 接/v, 上/f, 嗷嗷/o, 嗷嗷/o, ~/nx, 人民/n, 的/uj, 好/a, 伙伴/n, 啊/y, 嗷嗷/o, 嗷/n, ~/nx]

          我记得1.2.2优化过度,可能产生图不连通的问题。

      • 博主大大你好,想请教两个问题
        1.在hanlp的1.2.4的版本中,我并未发现AhoCorasickSegment.java这个文件,com/hankcs/hanlp/dictionary/CustomDictionary.java,这里排重代码也不是147行,应该是151到154行,请问若 自定义词典和核心词典冲突的话,如何实现是用户自定义词典优先?(手动修改了下,但是貌似没有实现)
        2.上面问题是基于CustomDictionary.insert("","")导入实现的,这个可以再删除词典缓存文件之后,能够直接加载相关文件生成自定义词性的词典么?本人手动测试过可以切出导入的词,但是对应的词性不对(在com.hankcs.hanlp.corpus.tag.Nature 中已经加了自定义词性)

        • 现在最新版已经不是1.2.4了,你可以去Github上编译一个。下面说的都是针对Github上的最新版的。
          1、最新版废除了AhoCorasickSegment,取而代之的是com/hankcs/hanlp/seg/Other/DoubleArrayTrieSegment.java和com/hankcs/hanlp/seg/Other/AhoCorasickDoubleArrayTrieSegment.java。最新版注释掉了排重代码,这已经使得自定义词典优先级更高。
          2、insert不会影响缓存,它存在的最初目的仅仅是为了debug或做demo,会拖慢分词速度,不建议用到生产环境中。

          • 还是需要麻烦博主一下

            按照博主说的,我在github上重新下了一份最新版,但是发现自定义词库的词性依旧无效,自定义的词可以切出来,可以保证这个词不会跟核心词典冲突,请问是什么原因?

          • 能分出来不一定说明不冲突,你试试调用com.hankcs.hanlp.dictionary.CoreDictionary#get(java.lang.String)这个词,如果能get到,说明核心词典中已经有了这个词,这就冲突了,只能删掉

          • 博主,我通过调用com.hankcs.hanlp.dictionary.CoreDictionary#get(java.lang.String)方法,发现核心词典确实不存在我自定义的词,其实那个词是不存在的,例如“第三地方方对方答复” 这种,所以保证不会冲突,但是切出来之后词性是名词,并不是我自定义的那个词性,希望博主帮我解答一下,这里可能不太方便,希望博主能够加我QQ:1174780613详聊,拜谢!!!

  2. 群主,如果,想在页面输入关键词,在服务器里进行文件的搜索,找出所有匹配关键词的文件,HanLp能实现吗?

  3. 请问 博主,在您的词典中的词性明显比《计算所汉语词性标记集ICTPOS3.0》多了好多,请问词性标识符都是什么意思呀?有没有相关的说明文档可供参考?

  4. 您好,博主。我想请教一下问题,就是您做的那个面向搜索引擎的索引分词是使用的什么技术?还有您的词典词语的词性是如何划分的?恳请回答,谢谢,由于最近做一个项目,运用您写的索引分词,效果不错,想学习一下。

  5. The method walkToLoad(ByteArray, BaseNode.ValueArray) in the type BaseNode is not applicable for the arguments (ByteArray,
    BaseNode<V>.ValueArray)
    在myeclipse中报错,请问这个要怎么样修改?

  6. javahanlpdatadictionaryCoreNatureDictionary.txt.bin (系统找不到指定的文件。)
    我没有找到CoreNatureDictionary.txt.bin文件

  7. 想向博主请教一个问题,我用用CRF++训练学习模型,训练数据是第一列是单字,第二列是字符特征,第三列是标记实体,解码过程该如何构建,请博主给个方案

  8. 请教博主: 目前我看1.1.2 版本中还不能支持对数量词的识别,如"廊坊19元语音王" 切分后的结果是: [廊坊/ns, 19/m, 元/q, 语音/n, 王/n]. 但是我想要的结果应该是[廊坊/ns, 19元/mq, 语音/n, 王/n]. 博主能从程序方面解决这个问题吗? 还有一个建议哈 ! 就是核心词库中的 147974的"餐 qv 1 " 我感觉不应该为动量词的.如"烧腊单人餐",切分之后的效果是:[烧腊/nf, 单人/b, 餐/qv] ,其实应该是名词.我认为哈 应该为: [烧腊/nf, 单人/b, 餐/ng]. 纯属个人观点!仅供参考哈!

    • 1、数量词识别并不复杂,如果前一个词是m后一个是q就合并它们。我会尽快加入这个功能,做一个配置方法交由用户开启。
      2、感谢你的建议,词典可以随便修改,欢迎你fork一份https://github.com/hankcs/HanLP ,然后将修改后的版本提交给我,这才体现了开源的好处。

  9. 请问下你那转移字典格式 /**
    * 地名词典路径
    */
    public static String PlaceDictionaryPath = "data/dictionary/place/ns.txt";
    /**
    * 地名词典转移矩阵路径
    */
    public static String PlaceDictionaryTrPath = "data/dictionary/place/ns.tr.txt"; 第二个转移矩阵路径怎么生成的文件。我现在想加一个医疗字典文件夹(里面放医疗行业的字典txt)。我看原来的加载路径都是到具体的文件,如果想增加核心字典内容,怎么弄,我能把路径改到文件夹吗?那转移矩阵该怎么弄?

  10. 博主,我发现了一个问题,感觉应该算是bug吧.如:对句子"HENDAY SALON亨迪·造型美发套餐" 或者是"5和小知在17" 进行分词时,则报异常java.lang.AssertionError: 构造空白节点会导致死循环!
    at com.hankcs.hanlp.seg.common.Vertex.<init>(Vertex.java:78)
    at com.hankcs.hanlp.seg.common.Vertex.<init>(Vertex.java:70)
    at com.hankcs.hanlp.seg.common.Vertex.<init>(Vertex.java:167)
    at com.hankcs.hanlp.seg.HiddenMarkovModelSegment$2.hit(HiddenMarkovModelSegment.java:444)
    at com.hankcs.hanlp.seg.HiddenMarkovModelSegment$2.hit(HiddenMarkovModelSegment.java:440)

    请教博主,如何解决? [呵呵]

    • 补充下 我使用的是 System.out.println(HanLP.segment("HENDAY SALON亨迪·造型美发套餐,"));
      还有 List<Term> termList = IndexTokenizer.segment("HENDAY SALON亨迪·造型美发套餐,");
      都是报异常的.

      • 你在用什么版本?我测试一切正常
        [5/m, 和/cc, 小知/nr, 在/p, 17/m]
        [HENDAY/nx, /w, SALON/nx, 亨迪·/nrf, 造型/n, 美发/vn, 套餐/n, ,/w]

        • 感谢楼主哈, 找到问题所在了,我用的是1.1.3版本, 不同的是,我添加了一个电信的词库.词库文件中多了几个空行.这就是问题的关键. 词库文件中是不能有空行的. [嘻嘻] 这么一个小问题 折腾了我小半天的时间…

  11. 你好,你是在分词还是在句法分析?无论是mini还是standard,在-Xms140m -Xmx140m -Xmn128m下分词测试一切正常。除非你外挂了一个超级大的用户词典,或者一下子输入几千万字的文本。

  12. 看到博主做出了这么多东西,太震撼了。感觉比NLPIR还高大上。请教个问题,博主所实现的所有分词算法,是不是基于部分词典?
    谢谢

    • 过奖了,不敢当,部分算法也是师从NLPIR。HanLP实现的分词算法分为3类:1、基于NGram模型(最短路、N最短路)2、基于字符BMES标注构词模型(CRF)3、基于词典机械分词(ACDAT自动机,DAT)

  13. 都是乱码是个什么情况,项目编码是utf8,我将词库调成utf8无效,utf8无BOM编码也无效,都是乱码

    • 请说明jar版本,data.zip版本,下载后的配置手续。如果你按照文档来,data.zip解压出来的是二进制词典缓存,程序根本不会读取文本文件,也就根本不会发生乱码。

      • 下载了1.1.5的jar,data 200多MB的那个和配置文件,然后解压data到D:/HanLP/,配置文件只改了root为D:/HanLP/,然后System.out.println(HanLP.segment("你好,欢迎使用HanLP!"));
        结果
        [��ã���ӭʹ��, HanLP, ��]

        我用IntelliJ IDEA14

  14. 请问一下,按照您的说明,我放了追加词典进自定义词典中,然后调整了properties,最后删除bin缓存,是否再次运行就会自动加载我自定义的词典。谢谢!

  15. CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; 现代汉语补充词库.txt; 全国地名大全.txt ns; 人名词典.txt; 机构名词典.txt; 上海地名.txt ns;data/dictionary/person/nrf.txt nrf;data/hpitaldata/医学相关.txt ns
    我增加了一个医学相关.txt 为什么分词的时候都没用呢?比如湖南盛和地产万博汇第三期,分词后为湖南, 万博, 地产,我在医学相关.txt加了万博汇 ns这个词,怎么才能生效??

    • 你得指明词频,万博汇 ns 1000
      或者这样调试:
      HanLP.Config.enableDebug(true);
      HanLP.Config.ShowTermNature = false;
      Segment segment = new DijkstraSegment();
      CustomDictionary.insert("万博汇", "ns 1000");
      System.out.println(segment.seg(
      "地产万博汇第三期"
      ));

  16. CoreNatureDictionary.ngram文件里面的内容有多种特殊的形式
    比如:始##始@我 代表我开头,末##末@我 代表我结尾
    那 “我@未##串” 是什么
    “未##专”@公园 代表什么
    “未##串@下行” 代表什么
    请问有没有简单的文档介绍

  17. 你好,1.我想知道可以把字典的文件内容放到数据库中么?每次分词的时候读取出来,以流的形式输出.
    2,短语的关联如何实现,比如有这样的关联关系(三强 》 人强,家强,国强),如果分词中有 家强 这个词时,将它转化成 三强,或者保存为 加强(三强),这样对应的关系。
    3,特有的词库是需要自己训练么,crf++?

  18. 哇塞。。好腻害。。 [委屈] 小菜鸟弱弱的问一句,我准备做基于模拟登录机制的方案抓取页面获取新浪微博的数据,采用TextRank算法对文本进行关键词提取。求大神指点一下,还有你做的那个关键字提取的Java源代码在哪里找哇~非常感谢。。。

  19. Caused by: java.lang.NumberFormatException: For input string: "1<input"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at com.hankcs.hanlp.dictionary.CoreDictionary.load(CoreDictionary.java:80)
    at com.hankcs.hanlp.dictionary.CoreDictionary.<clinit>(CoreDictionary.java:40)

  20. 按照你提供的方法,修改了data /dictionary / person / nr.txt,加入一个新词条,但是系统依然误判。
    比如:“万余元” 本不该是人名,添加该词条,但是最终结果依然误判!求解决方法。

  21. 你好,我用了你的工具,但是我自定义的词典在分词时有时候还是不会被分出来,请问你的工具对用户词典的优先级是最高的吗?

  22. 博主你好!在我最近做的一个项目中,你的开源程序给了我极大的帮助。在此表示万分感谢与敬意。
    现在我想利用你的句法分析功能判断输入的句子是不是病句,但这似乎涉及到语言方面的问题。
    我们现在想的是 是不是要设计一个句式库,把每句话句法分析之后与库中句式对比,判断是否存在。以此判断病句。但是感觉这过程中似乎有很多不靠谱的地方。
    我想问问博主你是否知道类似的库,或者你对我们这个病句判断功能有没有自己的想法。
    再次感谢博主!
    另外,忙完这个实验室的项目我就可以放暑假回上海了。我想请博主吃个饭以表达感谢与崇敬之情,顺便了解一下博主作为一个码农学姐的学习历程。不知是否方便

    • 你好,感谢使用。
      抱歉最近有点忙,拖到现在才回复。
      中文句法分析是个很复杂的问题,目前做得最好的斯坦福句法分析器也只有百分之八十的准确率,放到开放语境中效果更差。如果句法分析器连正确的句子都经常分析错,那么就会干扰病句的识别了。
      我没有尝试过类似的试验,从写论文的角度讲,或许可以将病句的句法树和正常句法树分别标注,训练一个二分类器之类的模型试试。
      另外,我大概有点忙坏了,可能没有时间。

  23. 博主你好!
    在我的笔记本上用hanlp的句法依存分析分析一句普通的句子一般需要半分钟的时间,哈工大的那个在线语言云只需一两秒,我想请问下这是硬件的问题吗?可以改进吗?
    实验室的学长对我这个结果不太满意,博主能大概跟我解释一下原因及改进方法吗?

  24. 博主大人你好!在下有三个问题想请教:
    1、您使用的依存关系是清华大学的那个是吗?请问有没有具体的每种关系的解释?
    2、在做句法分析的时候标点符号算怎样的存在?当我分析一篇文章时,我是否需要将每句话的句号都去掉后再进行句法分析?
    3、输入“目前我国儿童医师的缺口大致在三十万”(这是央视用的一句完整的句子)核心成份是“医师”,输入“目前我国儿童医师的缺口大致是在三十万”(加一个“是”)核心成份是“是”,输入“我在上海”核心成份是“上海”。我想请问这三种结果里是否有不符合预期的结果?还是说都可以满足使用需求?
    特别是当句子里的“是”被省略只有介词“在”之类的时候。

  25. 博主,我用1.2.4版本跑NLP分词的例子,得到的第一个“教授”不是名词,请问问题可能出在哪里?

    [中国科学院/nt, 计算/v, 技术/n, 研究所/nis, 的/ude1, 宗成庆/nr, 教授/v, 正在/d, 教授/v, 自然/n, 语言/n, 处理/vn, 课程/n]

  26. 博主,您好,我用NLP分词跑了一些带有时间的例子之后,发现对时间的实体切分把数字和时间单位切分开了,怎么可以使其不要分开
    [2013/m, 年/qt, 4/m, 月/n, 27/m, 日/qt, 11/m, 时/qt, 54/m, 分/qt, ,/w, 在/p, 成都市/ns, 春熙路/ns, 附近/f]

    • String text = "2013年4月27日11时54分";
      NLPTokenizer.SEGMENT.enableNumberQuantifierRecognize(true);
      System.out.println(NLPTokenizer.segment(text));

      [2013年/mq, 4月/mq, 27日/mq, 11时/mq, 54分/mq]

    • System.out.println(HanLP.segment("“你看过匆匆匆那年"吗"));

      [“/w, 你/rr, 看过/v, 匆匆/z, 匆/n, 那年/r, "/w, 吗/y]

      我记得1.2.2优化过度,可能产生图不连通的问题。

  27. 博主,您好,就是我希望能分出类似"FZ-234"这种代表型号的词,是一个整体,我在词典中添加了这个整体的词和词性有的会分出来,有的却会被分开,比如:"XH-60型" [XH-/nx 60/m 型/nz] "XH-60A" [XH-/nx 60/m A/nx]

    • 技术问题请在Github上发issue,大家一起讨论。留言、私信无法保证即时回复。

      反馈问题的时候最好附上版本号、触发代码,节省彼此的时间。

  28. 博主,我在追加了人名词典后,出现了一个问题。严重: 自定义词典dependency/dictionary/custom/people_name.txt读取错误!java.lang.IllegalArgumentException: No enum constant com.hankcs.hanlp.corpus.tag.Nature.Knight
    请问这是怎么回事?是有英文名字就不行吗?

    • 词典目前是按空格分隔词和词性的,英文名字中间有空格,导致后半部分被当做词性了。
      先将原始词典中的空格换成制表符,然后将com/hankcs/hanlp/dictionary/CustomDictionary.java的148行的line.split("\s");改为line.split("t");即可。
      下一版会默认以t分隔。

  29. 博主你好,我又来了,在拜读HanLP的代码的时候,我对于你计算分词路径代价和词性路径代价的时候的采用的计算公式比较好奇,想请教一下HanLP中分词算法等的路径代价计算公式主要参考了哪些论文或者文献?主要就是我上面说的两个的公式,烦请解答,谢谢!

      • 前者是从中科院ICTCLAS开源代码中学到的计算式,详细考据的话可以追溯到某个人申请的专利(其实就是BiGram+平滑而已,Google下可以找到);后者标准版维特比是看了wiki后自己写的,效果和wiki中的Python代码完全一致,Simply版本是自己写的伪维特比-贪心算法,适用于对效果要求不高的场合。

  30. 博主您好,我在使用HanLP依存句法分析器,它不支持用户词典。请问如果我希望依存句法分析器在分词时的词典中加入我的词,或者使其根据我其他分词器分词的结果做依存句法分析有办法吗?

  31. 您好,我在自定义那里加了自己的词典,在加载的时候遇到了错误严重: 自定义词典E:/hanlp/data-for-1.2.4/data/dictionary/custom/360dict.txt读取错误!java.lang.IllegalArgumentException: No enum constant com.hankcs.hanlp.corpus.tag.Nature.comb。但是也生成了bin文件,而且比之前的bin文件要大。请问是什么原因呢?我的360dict.txt中的格式是词语 词性 词频。使用的hanlp是1,2.4版本的。谢谢!

  32. 你好,报错信息已经说得很清楚了,没有comb这个enum值。词性是enum类型,不是string,所以你需要往Nature enum类里面加自定义词性

  33. 博主,您好,我发现分词里面很多算法比如有时候能把男人这个词分出来,有时候却分到后面了。比如“高高的鼻梁无可挑剔,薄薄的唇瓣勾勒出男人才有的性感弧度”这句话里面把男人分开了,分成了[高高的, 鼻梁, 无可, 挑剔, ,, 薄薄的, 唇瓣, 勾勒, 出, 男, 人才, 有的, 性感, 弧度]。而”只有男人才能举起那么重的东西”这句话又能够把男人分出来,分词结果是[只有, 男人, 才能, 举起, 那么, 重, 的, 东西]。为什么会有这种情况呢?

  34. 因为训练语料中根本没有 男人 才 这样的句子,人民日报当然不会写这么暧昧的句子。请Google一下BiGram原理。解决方案是https://github.com/hankcs/HanLP/commit/f1300b10b914381da769c606928bacb09447aea8

  35. 请问 “ data/dictionary/other/CharType.dat.yes”这个文件是什么意思呢,我还原了一下 对应:
    (ǚ|474, ǚ|474) 17
    (Ǜ|475, Ǜ|475) 6
    (ǜ|476, ǜ|476) 17
    (ǝ|477, ɐ|592) 6
    (ɑ|593, ɑ|593) 17
    (ɒ|594, ɠ|608) 6
    (ɡ|609, ɡ|609) 17
    (ɢ|610, ˉ|713) 6
    (ˊ|714, ˋ|715) 17
    (ˌ|716, ˘|728) 6
    (˙|729, ˙|729) 17
    (˚|730, ΐ|912) 6
    (Α|913, Ρ|929) 17
    请问这个是怎么生成的啊,为什恶魔要这么做呢,有点不明白,谢谢博主

  36. 在我电脑上显示CoreDictionary.trie.parseText()这个方法找不到,我在源码看了,确实没有这个parseText(),请问是什么回事?

  37. 博主–额又来请教你了,在1.2.7版本中,用户自定义字典的优先级已经比核心词库要高了,为什么,词性还是会出问题呢。。比如说 肯德基在核心词库中是 “nf”, 在自定义中是 “ns”, 识别出来确实“nf”, 这个可能问题出在哪里了呢?还有一个问题就是:自定义字典中 无论是 “DAT” 还是Bintree 的方式添加,优先级都是最高的吧? 麻烦博主了

    • 支持,web项目结构比较复杂,建议你先print一下”./”目录,确定“./”在什么位置,然后基于./配置相对路径。
      File file=new File(“.”);
      String path=file.getAbsolutePath();
      根据这个path配相对路径就行了。

  38. 你好,我是用的1.2.8的版本,按文档说明,用户自定义词典已经比核心词典的优先级高了,但是是不是现在依然不会绝对的按照用户自定义词典来分,比如“叶凡是谁”,将“叶凡”加入用户词典依然不能正确分出来,分词结果是“叶 凡是 谁”,将“叶凡”的在词典中的频次调的很高也不能保证。

  39. 博主您好,1.2.8版本, 功能19. 文本推荐,我测试搜索词推荐,实际场景词或句子很多,我应该加载哪个词库呢?还是要自己准备词库?词库通常比较大,会不会出现内存溢出?

  40. [嘻嘻] 多谢LZ,因为我搜索的用的是elasticsearch,所以分词就用了IK的,自己也做了一些修改,在此基础上,用了你的pagerank算法实现,不管是提取关键词还是句子都蛮好用的,并且有注明作者,感谢博主。

  41. 博主,为啥分词时总将类似“互联网金融”的词分成了“互联网””金融“两个词呢,我在自定义词典里有添加”互联网金融“这个词的

  42. 博主你好,我在按照您的方式进行CRF分词的时候出现了以下错误: com.hankcs.hanlp.seg.CRF.CRFSegment$CharTable
    严重: 字符正规化表加载失败,原因如下:
    java.io.FileNotFoundException: datadictionaryotherCharTable.bin.yes (系统找不到指定的路径。)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(Unknown Source)
    at java.io.FileInputStream.(Unknown Source)
    at java.io.FileInputStream.(Unknown Source)
    at com.hankcs.hanlp.seg.CRF.CRFSegment$CharTable.(CRFSegment.java:368)
    at com.hankcs.hanlp.seg.CRF.CRFSegment.segSentence(CRFSegment.java:46)
    at com.hankcs.hanlp.seg.Segment.seg(Segment.java:422)
    at CRFSegment.CRF_Segment.crf_Segment(CRF_Segment.java:35)
    这个是什么原因,配置出错了,还是?请博主大大指教!O(∩_∩)O谢谢

  43. 博主你好!
    string str = “中国科学院计算技术研究所的宗成庆教授正在教授自然语言处理课程”;
    我用C#调用HanLP.segment(str);发现停用词没起作用,就是结果中不要出现“的”之类的在stopwords.txt中配置的词,该怎么配置呢?谢谢!

  44. 之前用Ansj,现刚发现HanLP,还不熟悉,但觉得HanLP非常不错。冒昧请教博主,我希望通过HanLP实现计算两个文章的相似度,盼大神提供使用HanLP实现文本相似度的大概思路或功能,感激不尽~我看https://github.com/ysc/word/tree/master/src/main/java/org/apdplat/word/analysis已有诸多算法实现,但我依然希望使用HanLP,可惜没有类似功能,着实遗憾。:-)

  45. 博主,您好!本人日前配置一套測試環境,其配置如下:
    Solr 5.2.1 + HanLP(hanlp-solr-plugin-1.0.3.jar,hanlp-portable-1.2.9.jar)+Tomcat 7.0.68+CentOS 6.7
    有關hanlp.properties的配置應該是正常,因為使用Solr Admin GUI的analysis命令輸入任何一段中文文章,如果是簡體字,則可以依據辭典來正常分詞,但是如果輸入繁體字,除了簡繁共用字有切分之外,其餘繁體中文字皆以單字切分,這個部分應該是詞典設定所造成,如果我加入繁體字詞典應該可以正常切分,問題來了:我將同義詞的詞典做了設定,使用analysis命令分析,畫面上卻沒有出現同義詞的分析結果,請問您有關此情況是不是我的設定有錯?補充一下:您的詞典有『云崖』,同義詞典也有定義『雲崖=云崖』,但是分析之後只會有『云崖』!

  46. 博主您好,我想修改一下CoreDictionary.txt文件,想往里加一些人名地名等实体丰富一下,可是总是报错Caused by: java.lang.IllegalArgumentException: No enum const class com.hankcs.hanlp.corpus.tag.Nature.Haring。这该怎么修改

    • 你好,请参考:https://github.com/hankcs/HanLP/wiki/FAQ#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%87%AA%E5%AE%9A%E4%B9%89%E8%AF%8D%E5%85%B8%E5%8A%A0%E8%BD%BD%E5%A4%B1%E8%B4%A5

  47. 楼主好,我直接调用句法分析器,
    System.out.println(CRFDependencyParser.compute(“把市场经济奉行的等价交换原则引入党的生活和国家机关政务活动中”));
    出现问题:
    java.lang.NullPointerException
    at com.hankcs.hanlp.dependency.CRFDependencyParser.parse(CRFDependencyParser.java:123)
    at com.hankcs.hanlp.dependency.AbstractDependencyParser.parse(AbstractDependencyParser.java:46)
    at com.hankcs.hanlp.dependency.CRFDependencyParser.compute(CRFDependencyParser.java:78)
    at bistu.idcc.features.ParseDependency.main(ParseDependency.java:19)
    应该如何解决

  48. 博主,想咨询一个问题,有没有想过,如果说文本分词是对文本的一个初始处理的话,那么语意预测还有知识库的建立,不知道博主有没有思考过,一个专业领域的文档知识,自动生成一个领域知识图谱或者知识库的情况,博士有思考过吗?

  49. 博主,想咨询一个问题,有没有想过,如果说文本分词是对文本的一个初始处理的话,那么语意预测还有知识库的建立,不知道博主有没有思考过,一个专业领域的文档知识,自动生成一个领域知识图谱或者知识库的情况,博士有思考过吗?

  50. Pingback: 自然语言的一些资料整理 | 牛吧大数据

  51. 博主您好,词库如果不用现成的,比如针对特殊领域的文章要怎么训练得到自己的词库?非常感谢!

  52. 博主你好,短语提取中 HanLP.extractPhrase(text, 5),第二个参数size指的是什么,换了几个数字测试,效果不明显,请问为什么?

  53. 你好 !我发现一个问题不知道是不是您故意为之。在提取关键词的时候单个字的名词 被过滤掉了吧,例如一篇关于熵的文章 竟然没有熵这个关键词,我看来你的源码 版本 1.3.1
    /**
    * 是否应当将这个term纳入计算,词性属于名词、动词、副词、形容词
    *
    * @param term
    * @return 是否应当
    */
    public boolean shouldInclude(Term term){

    default:
    {
    if (term.word.trim().length() > 1 && !CoreStopWordDictionary.contains(term.word))
    {
    return true;
    }
    } //这句话是不是有点不妥? 希望能及时收到回复!我的邮箱 515504936@qq.com

    }

我的开源项目

HanLP自然语言处理包基于DoubleArrayTrie的Aho Corasick自动机