lucene 分词实现

一、概念认识

1、常用的Analyer

SimpleAnalyzer、StopAnalyzer、WhitespaceAnalyzer、StandardAnalyzer

2、TokenStream

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

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

3、Tokenizer

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

4、TokenFilter

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

5、内置常用分词器分词进行分词的差异

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public  static  void  displayToken(String str,Analyzer a) {
         try  {
             TokenStream stream = a.tokenStream( "content" , new  StringReader(str));
             //创建一个属性,这个属性会添加流中,随着这个TokenStream增加
             CharTermAttribute cta = stream.addAttribute(CharTermAttribute. class );
             while (stream.incrementToken()) {
                 System.out.print( "[" +cta+ "]" );
             }
             System.out.println();
         catch  (IOException e) {
             e.printStackTrace();
         }
     }
?
1
2
3
4
5
6
7
8
9
public  Map<String,Analyzer> toMap(String[] str,Analyzer ... analyzers){
         Map<String,Analyzer> analyzerMap =  new  HashMap<String,Analyzer>();
         int  i = 0 ;
         for (Analyzer a : analyzers){
             analyzerMap.put(str[i], a);
             i++;
         }
         return  analyzerMap;
     }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
     public  void  test01() {
         String[] str ={ "StandardAnalyzer" , "StopAnalyzer" , "SimpleAnalyzer" , "WhitespaceAnalyzer" };
         Map<String,Analyzer> analyzerMap =  new  HashMap<String,Analyzer>();
         
         Analyzer a1 =  new  StandardAnalyzer(Version.LUCENE_35);
         Analyzer a2 =  new  StopAnalyzer(Version.LUCENE_35);
         Analyzer a3 =  new  SimpleAnalyzer(Version.LUCENE_35);
         Analyzer a4 =  new  WhitespaceAnalyzer(Version.LUCENE_35);
         
         analyzerMap = toMap(str,a1,a2,a3,a4);
         
         String txt =  "this is my house,I am come from bilibili qiansongyi,"  +
                 "My email is dumingjun@gmail.com,My QQ is 888168" ;
         
         for (String analyzer : analyzerMap.keySet()){
             System.out.println(analyzer);
             AnalyzerUtils.displayToken(txt, analyzerMap.get(analyzer));
             System.out.println( "==============================" );
         }
     }

6、中文分词

?
1
2
3
4
5
6
7
8
9
public  void  toMap(String txt,Analyzer ... analyzers){
         for (Analyzer a : analyzers){
             int  start = a.toString().lastIndexOf( "." )+ 1 ;
             int  end = a.toString().lastIndexOf( "@" )- 1 ;
             System.out.println(a.toString().substring(start, end));
             AnalyzerUtils.displayToken(txt, a);
             System.out.println( "====================" );
         }
     }
?
1
2
3
4
5
6
7
8
9
10
public  void  test02() {
         Analyzer a1 =  new  StandardAnalyzer(Version.LUCENE_35);
         Analyzer a2 =  new  StopAnalyzer(Version.LUCENE_35);
         Analyzer a3 =  new  SimpleAnalyzer(Version.LUCENE_35);
         Analyzer a4 =  new  WhitespaceAnalyzer(Version.LUCENE_35);
         Analyzer a5 =  new  MMSegAnalyzer( new  File( "D:\\lucene\\mmseg4j\\data" ));
         String txt =  "我来自中国广东省广州市天河区的小白" ;
         
         toMap(txt,a1,a2,a3,a4,a5);
     }

7、位置增量、位置偏移量、分词单元、分词器的类型

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public  static  void  displayAllTokenInfo(String str,Analyzer a) {
         try  {
             TokenStream stream = a.tokenStream( "content" , new  StringReader(str));
             //位置增量的属性,存储语汇单元之间的距离
             PositionIncrementAttribute pia = 
             stream.addAttribute(PositionIncrementAttribute. class );
             //每个语汇单元的位置偏移量
             OffsetAttribute oa = stream.addAttribute(OffsetAttribute. class );
             //存储每一个语汇单元的信息(分词单元信息)
             CharTermAttribute cta = stream.addAttribute(CharTermAttribute. class );
             //使用的分词器的类型信息
             TypeAttribute ta = 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();
         }
     }

8、停用分词器

?
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
public  class  MyStopAnalyzer  extends  Analyzer {
     @SuppressWarnings ( "rawtypes" )
     private  Set stops;
     @SuppressWarnings ( "unchecked" )
     public  MyStopAnalyzer(String[]sws) {
         //会自动将字符串数组转换为Set
         stops = StopFilter.makeStopSet(Version.LUCENE_35, sws,  true );
         //将原有的停用词加入到现在的停用词
         stops.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);
     }
     
     public  MyStopAnalyzer() {
         //获取原有的停用词
         stops = StopAnalyzer.ENGLISH_STOP_WORDS_SET;
     }
 
     @Override
     public  TokenStream tokenStream(String fieldName, Reader reader) {
         //为这个分词器设定过滤链和Tokenizer
         return  new  StopFilter(Version.LUCENE_35,
                new  LowerCaseFilter(Version.LUCENE_35, 
                new  LetterTokenizer(Version.LUCENE_35,reader)), stops);
     }
 
}
?
1
2
3
4
5
6
7
8
@Test
     public  void  test04() {
         Analyzer a1 =  new  MyStopAnalyzer( new  String[]{ "I" , "you" , "hate" });
         Analyzer a2 =  new  MyStopAnalyzer();
         String txt =  "how are you thank you I hate you" ;
         AnalyzerUtils.displayToken(txt, a1);
         AnalyzerUtils.displayToken(txt, a2);
     }

9、简单实现同义词索引

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  class  MySameAnalyzer  extends  Analyzer {
     private  SamewordContext samewordContext;
     
     public  MySameAnalyzer(SamewordContext swc) {
         samewordContext = swc;
     }
 
     @Override
     public  TokenStream tokenStream(String fieldName, Reader reader) {
         Dictionary dic = Dictionary.getInstance( "D:\\lucene\\mmseg4j\\data" );
         return  new  MySameTokenFilter(
                 new  MMSegTokenizer( 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
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
public  class  MySameTokenFilter  extends  TokenFilter {
     private  CharTermAttribute cta =  null ;
     private  PositionIncrementAttribute pia =  null ;
     private  AttributeSource.State current;
     private  Stack<String> sames =  null ;
     private  SamewordContext samewordContext;
 
     protected  MySameTokenFilter(TokenStream input,SamewordContext samewordContext) {
         super (input);
         cta =  this .addAttribute(CharTermAttribute. class );
         pia =  this .addAttribute(PositionIncrementAttribute. class );
         sames =  new  Stack<String>();
         this .samewordContext = samewordContext;
     }
 
     @Override
     public  boolean  incrementToken()  throws  IOException {
         if (sames.size()> 0 ) {
             //将元素出栈,并且获取这个同义词
             String str = sames.pop();
             //还原状态
             restoreState(current);
             cta.setEmpty();
             cta.append(str);
             //设置位置0
             pia.setPositionIncrement( 0 );
             return  true ;
         }
         
         if (! this .input.incrementToken())  return  false ;
         
         if (addSames(cta.toString())) {
             //如果有同义词将当前状态先保存
             current = captureState();
         }
         return  true ;
     }
     
     private  boolean  addSames(String name) {
         String[] sws = samewordContext.getSamewords(name);
         if (sws!= null ) {
             for (String str:sws) {
                 sames.push(str);
             }
             return  true ;
         }
         return  false ;
     }
     
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  SimpleSamewordContext2  implements  SamewordContext {
     
     Map<String,String[]> maps =  new  HashMap<String,String[]>();
     public  SimpleSamewordContext2() {
         maps.put( "中国" , new  String[]{ "天朝" , "大陆" });
     }
 
     @Override
     public  String[] getSamewords(String name) {
         return  maps.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
@Test
     public  void  test05() {
         try  {
             Analyzer a2 =  new  MySameAnalyzer( new  SimpleSamewordContext2());
             String txt =  "我来自中国广东省广州市天河区的小白" ;
             Directory dir =  new  RAMDirectory();
             IndexWriter writer =  new  IndexWriter(dir, new  IndexWriterConfig(Version.LUCENE_35, a2));
             Document doc =  new  Document();
             doc.add( new  Field( "content" ,txt,Field.Store.YES,Field.Index.ANALYZED));
             writer.addDocument(doc);
             writer.close();
             IndexSearcher searcher =  new  IndexSearcher(IndexReader.open(dir));
             TopDocs tds = searcher.search( new  TermQuery( new  Term( "content" , "咱" )), 10 );
//          Document d = 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();
         }
     }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值