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 }