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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM