开发者社区> 科技小能手> 正文

第四章 分词

简介:
+关注继续查看

4.1 分词器的核心类

1. Analyzer

       Lucene内置分词器SimpleAnalyzerStopAnalyzerWhitespaceAnalyzerStandardAnalyzer

主要作用:

KeywordAnalyzer分词,没有任何变化;

SimpleAnalyzer对中文效果太差;

StandardAnalyzer对中文单字拆分;

StopAnalyzerSimpleAnalyzer差不多;

WhitespaceAnalyzer只按空格划分。

 

2. TokenStream

分词器做好处理之后得到的一个流,这个流中存储了分词的各种信息,可以通过TokenStream有效的获取到分词单元信息

生成的流程

wKiom1QNXCjRDia8AAC0d1oqgS8802.jpg

在这个流中所需要存储的数据

wKioL1QNXD_D-wnJAADBZV4ljMM627.jpg

3. Tokenizer

主要负责接收字符流Reader,Reader进行分词操作。有如下一些实现类

wKiom1QNXGHBgyjGAAFfL_LVWgc751.jpg


4. TokenFilter

将分词的语汇单元,进行各种各样过滤

wKioL1QNXH7Rb2ESAADkQpvbtrs160.jpg


5.扩展:TokenFilter各类介绍:

(1),TokenFilter

输入参数为另一个TokerStreamTokerStream,其子类必须覆盖incrementToken()函数。

 

(2),LowerCaseFilter

Token分词转换为小写。

 

(3),FilteringTokenFilter

 

TokenFilters的一个抽象类,可能会删除分词。如果当前分词要保存,则需要实现accept()方法

并返回一个boolean值。incrementToken()方法将调用accept()方法来决定是否将当前的分词返回

给调用者。

 

(4),StopFilter

token stream中移除停止词(stop words.

1
2
3
protected boolean accept() {
     return!stopWords.contains(termAtt.buffer(), 0, termAtt.length());//返回不是stop word的分词
 }

(5),TypeTokenFilter

token stream中移除指定类型的分词。

1
2
3
protected boolean accept() {
     returnuseWhiteList == stopTypes.contains(typeAttribute.type());
}

(6),LetterTokenizer

是一个编译器,将文本在非字母。说,它定义了令牌的最大字符串相邻的字母

 

 

(7),TokenFilter的顺序问题

此时停止词 the 就未被去除了。先全部转换为小写字母,再过滤停止词(The 转换成 the 才可以与停止词词组里的 the 匹配),如果不限制大小写,停止词的组合就太多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.Reader;
import java.util.Set;
import org.apache.lucene.analysis.Analyzer;
importorg.apache.lucene.analysis.LetterTokenizer;
importorg.apache.lucene.analysis.LowerCaseFilter;
import org.apache.lucene.analysis.StopAnalyzer;
import org.apache.lucene.analysis.StopFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.util.Version;
public class MyStopAnalyzer extends Analyzer {
  privateSet<Object> words;
  publicMyStopAnalyzer(){}
  publicMyStopAnalyzer(String[] words ){
     this.words=StopFilter.makeStopSet(Version.LUCENE_35,words, true);
     this.words.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET)
  }
  
  @Override
  publicTokenStream tokenStream(String fieldName, Reader reader) {
     // TODO Auto-generatedmethod stub
     return newStopFilter(Version.LUCENE_35,new LowerCaseFilter(Version.LUCENE_35, newLetterTokenizer(Version.LUCENE_35,reader)),this.words);
  }
}

4.2Attribute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void displayAllTokenInfo(Stringstr,Analyzer a) {
           try{
                 TokenStreamstream = a.tokenStream("content",new StringReader(str));
                 //位置增量的属性,存储语汇单元之间的距离
                 PositionIncrementAttributepia = 
                                  stream.addAttribute(PositionIncrementAttribute.class);
                 //每个语汇单元的位置偏移量
                 OffsetAttributeoa = 
                                  stream.addAttribute(OffsetAttribute.class);
                 //存储每一个语汇单元的信息(分词单元信息)
                 CharTermAttributecta = 
                                  stream.addAttribute(CharTermAttribute.class);
                 //使用的分词器的类型信息
                 TypeAttributeta = 
                                  stream.addAttribute(TypeAttribute.class);
                 for(;stream.incrementToken();){
                      System.out.print(pia.getPositionIncrement()+":");
                      System.out.print(cta+"["+oa.startOffset()+"-"+oa.endOffset()+"]-->"+ta.type()+"\n");
                 }
           }catch (Exception e) {
                 e.printStackTrace();
           }
      }

4.3 自定义分词器

1.自定义Stop分词器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.mzsx.analyzer;
  
import java.io.Reader;
import java.util.Set;
  
import org.apache.lucene.analysis.Analyzer;
importorg.apache.lucene.analysis.LetterTokenizer;
importorg.apache.lucene.analysis.LowerCaseFilter;
import org.apache.lucene.analysis.StopAnalyzer;
import org.apache.lucene.analysis.StopFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.util.Version;
  
public class MyStopAnalyzer extends Analyzer {
      privateSet<Object> words;
      publicMyStopAnalyzer(){}
      publicMyStopAnalyzer(String[] words ){
           this.words=StopFilter.makeStopSet(Version.LUCENE_35,words, true);
           this.words.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);
            
      }
  
      @Override
      publicTokenStream tokenStream(String fieldName, Reader reader) {
           returnnew StopFilter(Version.LUCENE_35,new LowerCaseFilter(Version.LUCENE_35, newLetterTokenizer(Version.LUCENE_35,reader)),this.words);
      }
}
1
2
3
4
5
6
7
8
9
//测试代码
@Test
      publicvoid myStopAnalyzer() {
           Analyzera1 = new MyStopAnalyzer(new String[]{"I","you","hate"});
           Analyzera2 = new MyStopAnalyzer();
           Stringtxt = "how are you thank you I hate you";
           AnalyzerUtils.displayAllTokenInfo(txt,a1);
           //AnalyzerUtils.displayToken(txt,a2);
      }


 

2.简单实现同义词索引

1
2
3
4
5
package com.mzsx.analyzer;
  
public interface SamewordContext {
      publicString[] getSamewords(String name);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.mzsx.analyzer;
  
import java.util.HashMap;
import java.util.Map;
  
public class SimpleSamewordContext implementsSamewordContext {
       
      Map<String,String[]>maps = new HashMap<String,String[]>();
      publicSimpleSamewordContext() {
           maps.put("中国",new String[]{"天朝","大陆"});
           maps.put("我",new String[]{"咱","俺"});
           maps.put("china",new String[]{"chinese"});
      }
  
      @Override
      publicString[] getSamewords(String name) {
           returnmaps.get(name);
      }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.mzsx.analyzer;
  
import java.io.IOException;
import java.util.Stack;
  
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
importorg.apache.lucene.analysis.tokenattributes.CharTermAttribute;
importorg.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.util.AttributeSource;
  
public class MySameTokenFilter extendsTokenFilter {
      privateCharTermAttribute cta = null;
      privatePositionIncrementAttribute pia = null;
      privateAttributeSource.State current;
      privateStack<String> sames = null;
      privateSamewordContext samewordContext;
  
      protectedMySameTokenFilter(TokenStream input,SamewordContext samewordContext) {
           super(input);
           cta= this.addAttribute(CharTermAttribute.class);
           pia= this.addAttribute(PositionIncrementAttribute.class);
           sames= new Stack<String>();
           this.samewordContext= samewordContext;
      }
  
      @Override
      publicboolean incrementToken() throws IOException {
           if(sames.size()>0){
                 //将元素出栈,并且获取这个同义词
                 Stringstr = sames.pop();
                 //还原状态
                 restoreState(current);
                 cta.setEmpty();
                 cta.append(str);
                 //设置位置0
                 pia.setPositionIncrement(0);
                 returntrue;
           }
            
           if(!this.input.incrementToken())return false;
            
           if(addSames(cta.toString())){
                 //如果有同义词将当前状态先保存
                 current= captureState();
           }
           returntrue;
      }
       
      privateboolean addSames(String name) {
           String[]sws = samewordContext.getSamewords(name);
           if(sws!=null){
                 for(Stringstr:sws) {
                      sames.push(str);
                 }
                 returntrue;
           }
           returnfalse;
      }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.mzsx.analyzer;
  
import java.io.Reader;
  
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
  
import com.chenlb.mmseg4j.Dictionary;
import com.chenlb.mmseg4j.MaxWordSeg;
importcom.chenlb.mmseg4j.analysis.MMSegTokenizer;
  
public class MySameAnalyzer extends Analyzer {
      privateSamewordContext samewordContext;
       
      publicMySameAnalyzer(SamewordContext swc) {
           samewordContext= swc;
      }
  
      @Override
      publicTokenStream tokenStream(String fieldName, Reader reader) {
           Dictionarydic = Dictionary.getInstance("D:/luceneIndex/dic");
           returnnew MySameTokenFilter(
                      newMMSegTokenizer(new MaxWordSeg(dic), reader),samewordContext);
      }
  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//测试代码
@Test
      publicvoid testSameAnalyzer() {
           try{
                 Analyzera2 = new MySameAnalyzer(new SimpleSamewordContext());
                 Stringtxt = "我来自中国海南儋州第一中学,welcome to china !";
                 Directorydir = new RAMDirectory();
                 IndexWriterwriter = new IndexWriter(dir,new IndexWriterConfig(Version.LUCENE_35, a2));
                 Documentdoc = new Document();
                 doc.add(newField("content",txt,Field.Store.YES,Field.Index.ANALYZED));
                 writer.addDocument(doc);
                 writer.close();
                 IndexSearchersearcher = new IndexSearcher(IndexReader.open(dir));
                 TopDocstds = searcher.search(new TermQuery(new Term("content","咱")),10);
                 Documentd = searcher.doc(tds.scoreDocs[0].doc);
                 System.out.println("原文:"+d.get("content"));
                 AnalyzerUtils.displayAllTokenInfo(txt,a2);
           }catch (CorruptIndexException e) {
                 e.printStackTrace();
           }catch (LockObtainFailedException e) {
                 e.printStackTrace();
           }catch (IOException e) {
                 e.printStackTrace();
           }
      }



本文转自 梦朝思夕 51CTO博客,原文链接:http://blog.51cto.com/qiangmzsx/1549902





版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
部分常用分词工具使用整理
以下分词工具均能在Python环境中直接调用(排名不分先后)。1、jieba(结巴分词) 免费使用2、HanLP(汉语言处理包) 免费使用3、SnowNLP(中文的类库) 免费使用4、FoolNLTK(中文处理工具包) 免费使用5、Jiagu(甲骨NLP) 免费使用6、pyltp(哈工大语言云) 商用需要付费7、THULAC(清华中文词法分析工具包) 商用需要付费8、NLPIR(汉语分词系统) 付费使用 1、jieba(结巴分词)“结巴”中文分词:做最好的 Python 中文分词组件。
1940 0
分词 概述
现有的分词算法可分为三大类:基于字符串匹配的分词方法、基于理解的分词方法和基于统计的分词方法。基于字符串匹配的分词方法 按照扫描方向的不同,串匹配分词方法可以分为正向匹配和逆向匹配;按照不同长度优先匹配的情况,可以分为最大(最长)匹配和最小(最短)匹配理解法 在分词的同时进行句法、语义分析,利用句法信息和语义信息来处理歧义现象。它通常包括三个部分:分词子系统、句法语义子系统、总控部分。
1577 0
菜鸟如何使用hanlp做分词的过程记录
最近在学习hanlp的内容,准备在节后看看有没有时间整理一波hanlp分享下,应该还是会像之前分享DKHadoop一样的方式吧。把整个学习的过程中截图在配文字的方式搞一下。 这两天也在看一些其他人分享的hanlp学习和使用分享的文章,后面看到的分享也会转载分享给大家。
1593 0
中文分词概述 | 学习笔记
快速学习中文分词概述
22 0
中文分词概述|学习笔记
快速学习中文分词概述。
19 0
分词工具Hanlp基于感知机的中文分词框架
结构化感知机标注框架是一套利用感知机做序列标注任务,并且应用到中文分词、词性标注与命名实体识别这三个问题的完整在线学习框架,该框架利用
1922 0
HanLP分词工具中的ViterbiSegment分词流程
本篇文章将重点讲解HanLP的ViterbiSegment分词器类,而不涉及感知机和条件随机场分词器,也不涉及基于字的分词器。因为这些分词器都不是我们在实践中常用的,而且ViterbiSegment也是作者直接封装到HanLP类中的分词器,作者也推荐使用该分词器,同时文本分类包以及其他一些自然语言处理任务包中的分词器也都间接使用了ViterbiSegment分词器。
901 0
【英文文本分类实战】之三——数据清洗
【英文文本分类实战】之三——数据清洗
24 0
NLP(2) | 中文分词分词的概念分词方法分类CRFHMM分词
NLP(2) | 中文分词分词的概念分词方法分类CRFHMM分词
57 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
中文:即学即用的Pandas入门与时间序列分析
立即下载
云栖专家带你技术进阶之全文检索和相似搜索实践
立即下载
O2O搜索优化实践之道
立即下载