zoukankan      html  css  js  c++  java
  • Lucene:Ansj分词器

    Ansj分词器

    导入jar

    ansj_seg-5.1.6.jar

    nlp-lang-1.7.8.jar

     maven配置

    <dependency>

    <groupId>org.ansj</groupId>

    <artifactId>ansj_seg</artifactId>

     <version>5.1.1</version>

     </dependency>

    代码演示

      1 import org.ansj.library.DicLibrary;
      2 import org.ansj.splitWord.analysis.*;
      3 import org.ansj.util.MyStaticValue;
      4 
      5 
      6 /**
      7  * AnsjAnalyzerTest
      8  *
      9  * @author limingcheng
     10  * @Date 2019/11/26
     11  */
     12 public class AnsjAnalyzerTest {
     13 
     14 
     15 
     16     /**
     17      * 基本分词(BaseAnalysis)
     18      * 速度快
     19      */
     20     public static void BaseAnalysisTest(){
     21         String words = "让战士们过一个欢乐祥和的新春佳节。";
     22         System.out.println(BaseAnalysis.parse(words));
     23     }
     24 
     25     /**
     26      * 精准分词(ToAnalysis)
     27      * 精准分词方式兼顾精度与速度,比较均衡
     28      */
     29     public static void ToAnalysisTest(){
     30         String words = "让战士们过一个欢乐祥和的新春佳节。";
     31         System.out.println(ToAnalysis.parse(words));
     32     }
     33 
     34     /**
     35      * NLP分词(NlpAnalysis)
     36      * NLP分词方式可是未登录词,但速度较慢
     37      */
     38     public static void NlpAnalysisTest(){
     39         String words = "洁面仪配合洁面深层清洁毛孔 清洁鼻孔面膜碎觉使劲挤才能出一点点皱纹 " +
     40                 "脸颊毛孔修复的看不见啦 草莓鼻历史遗留问题没辙 脸和脖子差不多颜色的皮肤才是健康的 " +
     41                 "长期使用安全健康的比同龄人显小五到十岁 28岁的妹子看看你们的鱼尾纹。";
     42         System.out.println(NlpAnalysis.parse(words));
     43     }
     44 
     45     /**
     46      * 面向索引分词(IndexAnalysis)
     47      */
     48     public static void IndexAnalysisTest(){
     49         String words = "洁面仪配合洁面深层清洁毛孔 清洁鼻孔面膜碎觉使劲挤才能出一点点皱纹";
     50         System.out.println(IndexAnalysis.parse(words));
     51     }
     52 
     53     /**
     54      * 自定词典分词(DicLibrary)
     55      * 动态添加
     56      */
     57     public static void DicLibraryTest(){
     58         //添加自定义词语 【 英文,按照小写配置。(大写,不识别。拆词的结果,也转为小写了)】
     59         DicLibrary.insert(DicLibrary.DEFAULT, "基于java", "n", 1);
     60 
     61         String text = "基于Java开发的轻量级的中分分词工具包";
     62 
     63         System.out.println(DicAnalysis.parse(text));
     64     }
     65 
     66     /**
     67      * 自定词典分词(DicLibrary)
     68      * 路径获取
     69      */
     70     public static void DicLibraryPath(){
     71         // 关闭名字识别
     72         MyStaticValue.isNameRecognition = false;
     73         // 配置自定义词典的位置。注意是绝对路径
     74         MyStaticValue.ENV.put(DicLibrary.DEFAULT, "E:\indexDir\library\default.dic");
     75 
     76         String text = "基于Java开发的轻量级的中分分词工具包";
     77 
     78         System.out.println(DicAnalysis.parse(text));
     79     }
     80 
     81     /**
     82      * 自定词典分词(DicLibrary)
     83      * 配置文件
     84      */
     85     public static void DicLibraryProperties(){
     86         String text = "基于Java开发的轻量级的中分分词工具包";
     87 
     88         System.out.println(DicAnalysis.parse(text));
     89     }
     90 
     91     public static void main(String[] args) {
     92         // 基本分词
     93 //        BaseAnalysisTest();
     94 //        // 精准分词
     95 //        ToAnalysisTest();
     96 //        // NLP分词
     97 //        NlpAnalysisTest();
     98 //        // 面向索引分词
     99 //        IndexAnalysisTest();
    100         // 词典分词(动态添加)
    101 //        DicLibraryTest();
    102         // 词典分词(路径)
    103 //        DicLibraryPath();
    104         // 词典分词(配置文件)
    105         DicLibraryProperties();
    106     }
    107 }

    1.1.5. 搭配Lucene

    由于Ansj项目并没有提供analyzer,需要自己手动写一个来适配。因此,首先要创建以下几个类:

    AnsjAnalyzer

      1 import org.ansj.library.*;
      2 import org.ansj.recognition.impl.StopRecognition;
      3 import org.ansj.recognition.impl.SynonymsRecgnition;
      4 import org.ansj.splitWord.Analysis;
      5 import org.ansj.splitWord.analysis.*;
      6 import org.apache.lucene.analysis.Analyzer;
      7 import org.apache.lucene.analysis.Tokenizer;
      8 import org.nlpcn.commons.lang.tire.domain.Forest;
      9 import org.nlpcn.commons.lang.tire.domain.SmartForest;
     10 import org.nlpcn.commons.lang.util.StringUtil;
     11 import org.nlpcn.commons.lang.util.logging.Log;
     12 import org.nlpcn.commons.lang.util.logging.LogFactory;
     13 
     14 import java.io.BufferedReader;
     15 import java.io.Reader;
     16 import java.io.StringReader;
     17 import java.util.ArrayList;
     18 import java.util.HashMap;
     19 import java.util.List;
     20 import java.util.Map;
     21 
     22 /**
     23  * AnsjAnalyzer
     24  *
     25  * @author limingcheng
     26  * @Date 2019/11/26
     27  */
     28 public class AnsjAnalyzer extends Analyzer {
     29    public static final Log LOG = LogFactory.getLog();
     30 
     31    /**
     32     * dic equals user , query equals to
     33     * 
     34     * @author ansj
     35     *
     36     */
     37    public static enum TYPE {
     38       // 基本分词(BaseAnalysis)
     39       base_ansj,
     40       // 索引分词
     41       index_ansj,
     42       // 查询分词
     43       query_ansj,
     44       // 自定词典分词(DicLibrary)
     45       dic_ansj,
     46       // NLP分词(NlpAnalysis)
     47       nlp_ansj
     48    }
     49 
     50    /**
     51     * 分词类型
     52     */
     53    private Map<String, String> args;
     54 
     55    /**
     56     * filter 停用词
     57     */
     58    public AnsjAnalyzer(Map<String, String> args) {
     59       this.args = args;
     60    }
     61 
     62    public AnsjAnalyzer(TYPE type, String dics) {
     63       this.args = new HashMap<String, String>();
     64       args.put("type", type.name());
     65       args.put(DicLibrary.DEFAULT, dics);
     66    }
     67 
     68    public AnsjAnalyzer(TYPE type) {
     69       this.args = new HashMap<String, String>();
     70       args.put("type", type.name());
     71    }
     72 
     73    @Override
     74    protected TokenStreamComponents createComponents(String text) {
     75       BufferedReader reader = new BufferedReader(new StringReader(text));
     76       Tokenizer tokenizer = null;
     77       tokenizer = getTokenizer(reader, this.args);
     78       return new TokenStreamComponents(tokenizer);
     79    }
     80 
     81    /**
     82     * 获得一个tokenizer
     83     * 
     84     * @param reader
     85     * @param args type
     86     * @param args filter
     87     * @return
     88     */
     89    public static Tokenizer getTokenizer(Reader reader, Map<String, String> args) {
     90       if (LOG.isDebugEnabled()) {
     91          LOG.debug("to create tokenizer " + args);
     92       }
     93       Analysis analysis = null;
     94 
     95       String temp = null;
     96       String type = args.get("type");
     97 
     98       if (type == null) {
     99          type = AnsjAnalyzer.TYPE.base_ansj.name();
    100       }
    101 
    102       switch (AnsjAnalyzer.TYPE.valueOf(type)) {
    103       case base_ansj:
    104          analysis = new BaseAnalysis();
    105          break;
    106       case index_ansj:
    107          analysis = new IndexAnalysis();
    108          break;
    109       case dic_ansj:
    110          analysis = new DicAnalysis();
    111          break;
    112       case query_ansj:
    113          analysis = new ToAnalysis();
    114          break;
    115       case nlp_ansj:
    116          analysis = new NlpAnalysis();
    117          if (StringUtil.isNotBlank(temp = args.get(CrfLibrary.DEFAULT))) {
    118             ((NlpAnalysis) analysis).setCrfModel(CrfLibrary.get(temp));
    119          }
    120          break;
    121       default:
    122          analysis = new BaseAnalysis();
    123       }
    124 
    125       if (reader != null) {
    126          analysis.resetContent(reader);
    127       }
    128 
    129       //用户自定义词典
    130       if (StringUtil.isNotBlank(temp = args.get(DicLibrary.DEFAULT))) {
    131          String[] split = temp.split(",");
    132          Forest[] forests = new Forest[split.length];
    133          for (int i = 0; i < forests.length; i++) {
    134             if (StringUtil.isBlank(split[i])) {
    135                continue;
    136             }
    137             forests[i] = DicLibrary.get(split[i]);
    138          }
    139          analysis.setForests(forests);
    140       }
    141 
    142       List<StopRecognition> filters = null;
    143       //用户自定义词典
    144       if (StringUtil.isNotBlank(temp = args.get(StopLibrary.DEFAULT))) {
    145          String[] split = temp.split(",");
    146          filters = new ArrayList<StopRecognition>();
    147          for (String key : split) {
    148             StopRecognition stop = StopLibrary.get(key.trim());
    149             if (stop != null) {
    150                filters.add(stop);
    151             }
    152          }
    153       }
    154 
    155       List<SynonymsRecgnition> synonyms = null;
    156       //同义词词典
    157       if (StringUtil.isNotBlank(temp = args.get(SynonymsLibrary.DEFAULT))) {
    158          String[] split = temp.split(",");
    159          synonyms = new ArrayList<SynonymsRecgnition>();
    160          for (String key : split) {
    161             SmartForest<List<String>> sf = SynonymsLibrary.get(key.trim());
    162             if (sf != null) {
    163                synonyms.add(new SynonymsRecgnition(sf));
    164             }
    165          }
    166       }
    167 
    168       //歧义词典
    169       if (StringUtil.isNotBlank(temp = args.get(AmbiguityLibrary.DEFAULT))) {
    170          analysis.setAmbiguityForest(AmbiguityLibrary.get(temp.trim()));
    171       }
    172 
    173       // 是否开启人名识别
    174       if (StringUtil.isNotBlank(temp = args.get("isNameRecognition"))) {
    175          analysis.setIsNameRecognition(Boolean.valueOf(temp));
    176       }
    177 
    178       // 是否开启数字识别
    179       if (StringUtil.isNotBlank(temp = args.get("isNumRecognition"))) {
    180          analysis.setIsNumRecognition(Boolean.valueOf(temp));
    181       }
    182 
    183       //量词识别
    184       if (StringUtil.isNotBlank(temp = args.get("isQuantifierRecognition"))) {
    185          analysis.setIsQuantifierRecognition(Boolean.valueOf(temp));
    186       }
    187 
    188       //是否保留原字符
    189       if (StringUtil.isNotBlank(temp = args.get("isRealName"))) {
    190          analysis.setIsRealName(Boolean.parseBoolean(temp));
    191       }
    192 
    193       return new AnsjTokenizer(analysis, filters, synonyms);
    194 
    195    }
    196 
    197 }

    AnsjTokenizer

    Ansj分词方式

    Ansj分词器提供了以下几种分词模式,各种分词模式都有各自的优劣势,适应不同的需求场景。参考:https://blog.csdn.net/lb521200200/article/details/53696387

    ToAnalysis 精准分词

    精准分词在易用性,稳定性.准确性.以及分词效率上.都取得了一个不错的平衡。万金油的存在,适合测试。

     DicAnalysis 用户自定义词典优先策略的分词

    用户自定义词典优先策略的分词。当分词效果不能满足要求,或者待分词的词语实在太过罕见的情况下,使用用户自定义词典可以有效解决该问题。

     NlpAnalysis 带有新词发现功能的分词

    NLP分词是一种分词效果比较好的分词方式,能识别出未登录词。同时效果极好的后果是消耗性能较大,导致速度比较慢、稳定性差(分词速度约为40w字每秒)。

    NLP的适用场景:语法实体名抽取;未登录词整理;只要是对文本进行发现分析等工作。

    1.2.4. IndexAnalysis 面向索引的分词

    面向索引的分词。顾名思义就是适合在lucene等文本检索中用到的分词。主要考虑以下两点

    召回率

    召回率是对分词结果尽可能的涵盖。比如对“上海虹桥机场南路” 召回结果是[上海/ns, 上海虹桥机场/nt, 虹桥/ns, 虹桥机场/nz, 机场/n, 南路/nr]

    准确率

    其实这和召回本身是具有一定矛盾性的Ansj的强大之处是很巧妙的避开了这两个的冲突 。比如我们常见的歧义句“旅游和服务”->对于一般保证召回 。大家会给出的结果是“旅游 和服 服务” 对于ansj不存在跨term的分词。意思就是。召回的词只是针对精准分词之后的结果的一个细分。比较好的解决了这个问题

    1.2.5. BaseAnalysis 最小颗粒度的分词

    基本就是保证了最基本的分词,词语颗粒度最非常小的。所涉及到的词大约是10万左右。基本分词速度非常快.macAir上,能到每秒300w字每秒。同时准确率也很高,但是对于新词他的功能十分有限。

    总结:

    功能统计:

    名称

    用户自定义词典

    数字识别

    人名识别

    机构名识别

    新词发现

    BaseAnalysis

    ToAnalysis

    DicAnalysis

    IndexAnalysis

    NlpAnalysis

    代码演示:

      1 package main.java.cn.lmc.collection.retrieval.web.analyzer;
      2 
      3 import org.ansj.domain.Result;
      4 import org.ansj.library.DicLibrary;
      5 import org.ansj.splitWord.analysis.*;
      6 import org.ansj.util.MyStaticValue;
      7 
      8 
      9 /**
     10  * AnsjAnalyzerTest
     11  *
     12  * @author limingcheng
     13  * @Date 2019/11/26
     14  */
     15 public class AnsjAnalyzerTest {
     16 
     17 
     18 
     19     /**
     20      * 基本分词(BaseAnalysis)
     21      * 速度快
     22      */
     23     public static void BaseAnalysisTest(){
     24         String words = "五月天创建的人生有限公司举报了一场演唱会,陈信宏唱了一首do you ever shine";
     25         System.out.println(BaseAnalysis.parse(words));
     26     }
     27 
     28     /**
     29      * 精准分词(ToAnalysis)
     30      * 精准分词方式兼顾精度与速度,比较均衡
     31      */
     32     public static void ToAnalysisTest(){
     33         String words = "五月天创建的人生有限公司举报了一场演唱会,陈信宏唱了一首do you ever shine。";
     34         System.out.println(ToAnalysis.parse(words));
     35     }
     36 
     37     /**
     38      * NLP分词(NlpAnalysis)
     39      * NLP分词方式可是未登录词,但速度较慢
     40      */
     41     public static void NlpAnalysisTest(){
     42         String words = "对对对对对对多多小学生 101304471127J";
     43         System.out.println(NlpAnalysis.parse(words));
     44         Result result = NlpAnalysis.parse(words);
     45         System.out.println(result.toString());
     46         System.out.println(result.getTerms().toString());
     47     }
     48 
     49     /**
     50      * 面向索引分词(IndexAnalysis)
     51      */
     52     public static void IndexAnalysisTest(){
     53         String words = "五月天创建的人生有限公司举报了一场演唱会,陈信宏唱了一首do you ever shine,周杰伦,杰伦";
     54         System.out.println(IndexAnalysis.parse(words));
     55         System.out.println(IndexAnalysis.parse("杰伦"));
     56     }
     57 
     58     /**
     59      * 自定词典分词(DicLibrary)
     60      * 动态添加
     61      */
     62     public static void DicLibraryTest(){
     63         //添加自定义词语 【 英文,按照小写配置。(大写,不识别。拆词的结果,也转为小写了)】
     64         DicLibrary.insert(DicLibrary.DEFAULT, "基于java", "n", 1);
     65 
     66         String text = "基于Java开发的轻量级的中分分词工具包";
     67 
     68         System.out.println(DicAnalysis.parse(text));
     69     }
     70 
     71     /**
     72      * 自定词典分词(DicLibrary)
     73      * 路径获取
     74      */
     75     public static void DicLibraryPath(){
     76         // 关闭名字识别
     77         MyStaticValue.isNameRecognition = false;
     78         // 配置自定义词典的位置。注意是绝对路径
     79         MyStaticValue.ENV.put(DicLibrary.DEFAULT, "E:\indexDir\library\default.dic");
     80 
     81         String text = "基于Java开发的轻量级的中分分词工具包";
     82 
     83         System.out.println(DicAnalysis.parse(text));
     84     }
     85 
     86     /**
     87      * 自定词典分词(DicLibrary)
     88      * 配置文件
     89      */
     90     public static void DicLibraryProperties(){
     91         String text = "基于Java开发的轻量级的中分分词工具包";
     92 
     93         System.out.println(DicAnalysis.parse(text));
     94     }
     95 
     96     public static void main(String[] args) {
     97         // 基本分词
     98 //        BaseAnalysisTest();
     99 //        // 精准分词
    100 //        ToAnalysisTest();
    101 //        // NLP分词
    102 //        NlpAnalysisTest();
    103 //        // 面向索引分词
    104         IndexAnalysisTest();
    105         // 词典分词(动态添加)
    106 //        DicLibraryTest();
    107         // 词典分词(路径)
    108 //        DicLibraryPath();
    109         // 词典分词(配置文件)
    110 //        DicLibraryProperties();
    111     }
    112 }
  • 相关阅读:
    Vue 获取URL链接后面的参数值
    Vue 跳转到指定页面,返回到上一页
    Vant 插件
    Vue 返回上一页,记住上一页的数据
    vue pc端支付宝支付
    Spring 中的事务
    数据库中锁与事务
    《产品方法论》 读书笔记
    设计模式之装饰者模式
    设计模式之单例模式
  • 原文地址:https://www.cnblogs.com/bestlmc/p/12304430.html
Copyright © 2011-2022 走看看