首页 > 编程语言 >Java分词器比较(ansj、hanlp、ik)

Java分词器比较(ansj、hanlp、ik)

时间:2023-02-28 16:25:51浏览次数:50  
标签:word String ik 词典 ansj result Java 分词

Java分词器比较(ansj、hanlp、ik)

一、分词工具

ansj、hanlp、ik

二、优缺点

1.ansj

优点:
  提供多种分词方式
  可直接根据内部词库分出人名、机构等信息
  可构造多个词库,在分词时可动态选择所要使用的词库
缺点:
  自定义词典时,系统词典还是被优先使用,导致词性不是自定义词典中的词性
  多单词英文姓名无法分出
适用场景

  若不使用自定义分词,可直接使用ansj

2.hanlp

优点:
  自定义分词、词性方便
  可分出多单词的英文名称(词典数据可带空格)
  可动态增删词库,
  动态添加词典前五千万速度很快,5m左右
缺点:
  动态添加词典前五千万快的很,越往后越慢
  词典文件添加自定义词典速度略慢,添加100w需要2m30s
适用场景:

  词典数量少于五千万,词典数据若包含空格,用hanlp比较合适

ansj的使用

1.maven引入ansj包

<ansj.version>5.0.4</ansj.version>
<tree_split.version>1.5</tree_split.version>
<nlp-lang.version>1.7.7</nlp-lang.version>

<!-- ansj_seg -->
<dependency>
  <groupId>org.ansj</groupId>
  <artifactId>ansj_seg</artifactId>
  <version>${ansj.version}</version>
</dependency>
<!-- tree_split -->
<dependency>
  <groupId>org.ansj</groupId>
  <artifactId>tree_split</artifactId>
  <version>${tree_split.version}</version>
</dependency>
<!-- nlp-lang -->
<dependency>
  <groupId>org.nlpcn</groupId>
  <artifactId>nlp-lang</artifactId>
  <version>${nlp-lang.version}</version>
</dependency>
  • 2.在项目根目录下创建library文件夹,文件夹下包括以下几个词典文件(自行添加)

ambiguity.dic
default.dic
userLibrary.dic

  • 3.使用
package com.zhen.segment;

import java.io.InputStream;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.library.UserDefineLibrary;
import org.ansj.splitWord.analysis.BaseAnalysis;
import org.ansj.splitWord.analysis.NlpAnalysis;
import org.ansj.splitWord.analysis.ToAnalysis;
import org.nlpcn.commons.lang.tire.domain.Forest;
import org.nlpcn.commons.lang.tire.domain.Value;
import org.nlpcn.commons.lang.tire.library.Library;

/**
 * @author FengZhen
 * @date Jan 30, 2019
 * ansj分词
 */
public class SegmentTest {

    public static void main(String[] args) {
      // dynamicWord();
      // localDic();
      // moreUserDic();
    }
    
    /**
     * 多用户词典(新增、删除)
     */
    public static void moreUserDic() {
        // 多用户词典
        String str = "神探夏洛克这部电影作者.是一个dota迷";
        System.out.println(ToAnalysis.parse(str));
        // 两个词汇 神探夏洛克 douta迷
        Forest dic1 = new Forest();
        Library.insertWord(dic1, new Value("神探夏洛克", "define", "1000"));
        Forest dic2 = new Forest();
        Library.insertWord(dic2, new Value("dota迷", "define", "1000"));
        System.out.println(ToAnalysis.parse(str, dic1, dic2));
        
        System.out.println("-------删除dic1中的词");
        Library.removeWord(dic1, "神探夏洛克");
        System.out.println(ToAnalysis.parse(str, dic1, dic2));
    }
    
    /**
     * 动态增删词库
     */
    public static void dynamicWord(){
        // 增加新词,中间按照'\t'隔开
        UserDefineLibrary.insertWord("ansj中文分词", "userDefine", 1000);
        Result result =  ToAnalysis.parse("我觉得Ansj中文分词是一个不错的系统!我是王婆!");
        System.out.println("增加新词例子:" + result);
        // 删除词语,只能删除.用户自定义的词典.
        UserDefineLibrary.removeWord("ansj中文分词");
        result = ToAnalysis.parse("我觉得ansj中文分词是一个不错的系统!我是王婆!");
        System.out.println("删除用户自定义词典例子:" + result);

        //将用户自定义词典清空
        UserDefineLibrary.clear();
    }

    /**
     * 加载词典文件
     */
    public static void localDic(){
        try {
            //读的是根目录下的
            Forest rootForest = Library.makeForest("library/userLibrary.dic");
            System.out.println(rootForest.toMap());
            //加载字典文件,取的是resource下的
            InputStream inputStream = SegmentTest.class.getResourceAsStream("/library/userLibrary.dic");
            Forest resoutceForest=Library.makeForest(inputStream);
            String str = "我觉得ansj中文分词是一个不错的系统!我是王婆!";
            Result result=ToAnalysis.parse(str, resoutceForest);//传入forest
            List<Term> termList=result.getTerms();
            for(Term term:termList){
                System.out.println(term.getName()+":"+term.getNatureStr());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 基本分词
     * 基本就是保证了最基本的分词.词语颗粒度最非常小的..所涉及到的词大约是10万左右.
     * 基本分词速度非常快.在macAir上.能到每秒300w字每秒.同时准确率也很高.但是对于新词他的功能十分有限
     * @param content
     */
    public static void baseAnay(String content) {
        Result result = BaseAnalysis.parse(delHTMLTag(content).replace("\n","").replace(" ", "").replace("\t",""));
        System.out.println("result:" + result);
    }

    /**
     * 精准分词
     * 它在易用性,稳定性.准确性.以及分词效率上.都取得了一个不错的平衡.
     * @param content
     */
    public static void toAnay(String content){
        Result result = ToAnalysis.parse(content);
        System.out.println("result:" + result);
    }

    /**
     * nlp分词(单条新闻处理7秒)
     * 可以识别出未登录词.但是它也有它的缺点.速度比较慢.稳定性差.ps:我这里说的慢仅仅是和自己的其他方式比较.应该是40w字每秒的速度吧.
     * 个人觉得nlp的适用方式.1.语法实体名抽取.未登录词整理.只要是对文本进行发现分析等工作
     * 会把企业分开
     * @param content
     */
    public static void nlpAnay(String content){
        Result result = NlpAnalysis.parse(delHTMLTag(content).replace("\n","").replace(" ", "").replace("\t",""));
        System.out.println("result:" + result);
        List<Term> terms = result.getTerms();
        for (Term term : terms) {
            String name = term.getName();
            String nature = term.getNatureStr();
            if (nature.equals("nt") || nature.equals("nr")) {
                System.out.println("------------------");
                System.out.println("getName:" + term.getName());
                System.out.println("getNatureStr:" + term.getNatureStr());
            }
        }
    }

    /**
     * 筛除HTML标签
     * @param htmlStr
     * @return
     */
    public static String delHTMLTag(String htmlStr){
        String regEx_script="<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
        String regEx_style="<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
        String regEx_html="<[^>]+>"; //定义HTML标签的正则表达式

        Pattern p_script=Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE);
        Matcher m_script=p_script.matcher(htmlStr);
        htmlStr=m_script.replaceAll(""); //过滤script标签

        Pattern p_style=Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE);
        Matcher m_style=p_style.matcher(htmlStr);
        htmlStr=m_style.replaceAll(""); //过滤style标签

        Pattern p_html=Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
        Matcher m_html=p_html.matcher(htmlStr);
        htmlStr=m_html.replaceAll(""); //过滤html标签

        return htmlStr.trim(); //返回文本字符串
    }
    
}

hanlp的使用

  • 1.maven添加依赖
<dependency>
    <groupId>com.hankcs</groupId>
    <artifactId>hanlp</artifactId>
    <version>portable-1.7.1</version>
</dependency>
  • 2.动态添加词
/**
 * 新增词
 */
public static void addWord(String word, NatureEnum nature) {
    logger.info("==== addWord@word:{},nature:{},weight:{} ====", word, nature.getNature(), nature.getWeight());
    if (!StringUtils.isBlank(word) && !word.equals("null")) {
        //大小括号问题
        if (word.contains("(") || word.contains(")")) {
            CustomDictionary.insert(word.replace("(", "(").replace(")", ")"), nature.getNature());
        }else if (word.contains("(") || word.contains(")")) {
            CustomDictionary.insert(word.replace("(", "(").replace(")", ")"), nature.getNature());
        }
        CustomDictionary.insert(word, nature.getNature());
    }else {
        logger.warn("==== addWord@ word({})为空 ====", word);
    }
}
  • 3.动态删除词
/**
 * 删除词
 * @param forest
 * @param word
 */
public static void deleteWord(String word) {
    logger.info("==== deleteWord@word:{} ====", word);
    if (!StringUtils.isBlank(word)) {
        CustomDictionary.remove(word);
    }else {
        logger.warn("==== deleteWord@word为空({}) ====", word);
    }
}
  • 4.使用
/**
 * 分词
 * @param content
 * @param forests
 * ToAnalysis精准分词
 * BaseAnalysis基础分词
 */
public static SegmentResult segment(String content) {
    logger.info("==== segment@content:{} ====", content);
    SegmentResult segmentResult = new SegmentResult();
    List<Term> terms = HanLP.segment(content);
    Set<String> companySet = new HashSet<String>();
    
    for (Term term : terms) {
        String name = term.word;
        String nature = term.nature.toString();
        if (nature.equals(NatureEnum.Company.getNature())) {
            companySet.add(name);
        }
    }
    segmentResult.setCompanys(new ArrayList<String>(companySet));
    logger.info("==== segment@分词结果:{},提取结果:{} ====", terms.toString(), segmentResult.toString());
    return segmentResult;
}
  • 5.自定义词典文件
    词典文件格式如下,依次是 词、词性、权重
    word nature weight

需要下载hanlp的data及hanlp.properties
https://github.com/hankcs/HanLP

data文件夹如下

标签:word,String,ik,词典,ansj,result,Java,分词
From: https://www.cnblogs.com/jockming/p/17164733.html

相关文章

  • JAVA基础学习
    学习记录第一部分Java基础第一章Java概述程序:为执行某些操作或解决某个问题而编写的一系列有序指令的集合。1.java重要特点面向对象(OOP)健壮跨平台性(一次编译......
  • Java数组
    Java数组什么是数组数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据成为一个数组元素,每个数组元素可......
  • java方法参数(超详细)
    前言在上一篇文章中,壹哥给大家讲解了方法的定义、调用和返回值,但方法的内容还有很多,比如方法的参数是怎么回事?接下来壹哥会在这篇文章中,继续给大家讲解方法参数相关的知识......
  • Java并发编程学习15-任务关闭(下)
    任务关闭(下)《任务关闭》由于篇幅较多,拆分了两篇来介绍各种任务和服务的关闭机制,以及如何编写任务和服务,使它们能够优雅地处理关闭。1.处理非正常的线程终止我们知道,当......
  • 剑指 Offer 55 - II. 平衡二叉树(java解题)
    目录1.题目2.解题思路3.数据类型功能函数总结4.java代码1.题目输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超......
  • Pig nacos 不支持 moxm/java:1.8-full 缺少 so 问题
    使用如下Dockerfile构建镜像#catDockerfileFROMmoxm/java:1.8-fullasbuilderWORKDIR/buildARGJAR_FILE=target/pig-register.jarCOPY${JAR_FILE}app.jarRU......
  • Java高级助教工作总结
    一、助教工作的具体职责和任务1.帮助老师在云班课上发布作业2.解答同学们的问题3.批改同学们的作业,并了解同学们的学习情况4.在qq群中发布通知,收集同......
  • java内存分配
                 ......
  • Java容器类List、ArrayList、Vector及map、HashTable、HashMap
    ArrayList和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引......
  • Java微基准测试神器JMH初探
    当我们编写一段Java代码之后,如果想知道代码性能如何,就需要进行一些快速的性能测试。当我们实现一个需求,面临2种及以上的方案,选择一种性能更好的方案时,也需要进行一些快速的......