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 }

 

相关文章