lucene第三步,分词

本文详细介绍了Java分词器在英文和中文分词下的比较,展示了不同分词器的特性与效果。同时,文章探讨了如何扩展自定义分词器,包括停用词分词器、同义词分词器等,提供了实现步骤与实例。最后,文章还介绍了如何打印语汇单元的详细信息和同义词过滤器的扩展。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

出自:http://blog.youkuaiyun.com/wxwzy738/article/details/8799656 的整理

1

2、语汇单元的结构解释


3、同义词的设计思路


4、分词器的比较和测试

  1. packageorg.lucene.test;
  2. importjava.io.File;
  3. importjava.io.IOException;
  4. importorg.apache.lucene.analysis.Analyzer;
  5. importorg.apache.lucene.analysis.SimpleAnalyzer;
  6. importorg.apache.lucene.analysis.StopAnalyzer;
  7. importorg.apache.lucene.analysis.WhitespaceAnalyzer;
  8. importorg.apache.lucene.analysis.standard.StandardAnalyzer;
  9. importorg.apache.lucene.document.Document;
  10. importorg.apache.lucene.document.Field;
  11. importorg.apache.lucene.index.CorruptIndexException;
  12. importorg.apache.lucene.index.IndexReader;
  13. importorg.apache.lucene.index.IndexWriter;
  14. importorg.apache.lucene.index.IndexWriterConfig;
  15. importorg.apache.lucene.index.Term;
  16. importorg.apache.lucene.search.IndexSearcher;
  17. importorg.apache.lucene.search.ScoreDoc;
  18. importorg.apache.lucene.search.TermQuery;
  19. importorg.apache.lucene.search.TopDocs;
  20. importorg.apache.lucene.store.Directory;
  21. importorg.apache.lucene.store.RAMDirectory;
  22. importorg.apache.lucene.util.Version;
  23. importorg.junit.Test;
  24. importorg.lucene.util.AnalyzerUtils;
  25. importorg.lucene.util.MySameAnalyzer;
  26. importorg.lucene.util.MyStopAnalyzer;
  27. importcom.chenlb.mmseg4j.analysis.MMSegAnalyzer;
  28. publicclassTestAnalyzer{
  29. /**
  30. *几种分词器在英文分词下面的比较
  31. */
  32. @Test
  33. publicvoidtest01(){
  34. //标准分词器
  35. Analyzera1=newStandardAnalyzer(Version.LUCENE_35);
  36. //停用词分词器
  37. Analyzera2=newStopAnalyzer(Version.LUCENE_35);
  38. //简单分词器
  39. Analyzera3=newSimpleAnalyzer(Version.LUCENE_35);
  40. //空格分词器
  41. Analyzera4=newWhitespaceAnalyzer(Version.LUCENE_35);
  42. Stringtxt="thisismyhouse,Iamcomefromyunnangzhaotong,"+
  43. "Myemailisynkonghao@gmail.com,MyQQis707807876";
  44. AnalyzerUtils.displayToken(txt,a1);
  45. //[my][house][i][am][come][from][yunnang][zhaotong][my][email][ynkonghao][gmail.com][my][qq][707807876]
  46. AnalyzerUtils.displayToken(txt,a2);
  47. //[my][house][i][am][come][from][yunnang][zhaotong][my][email][ynkonghao][gmail][com][my][qq]
  48. AnalyzerUtils.displayToken(txt,a3);
  49. //[this][is][my][house][i][am][come][from][yunnang][zhaotong][my][email][is][ynkonghao][gmail][com][my][qq][is]
  50. AnalyzerUtils.displayToken(txt,a4);
  51. //[this][is][my][house,I][am][come][from][yunnang][zhaotong,My][email][is][ynkonghao@gmail.com,My][QQ][is][707807876]
  52. }
  53. /**
  54. *几种分词器在中文分词下面的比较
  55. */
  56. @Test
  57. publicvoidtest02(){
  58. //标准分词器
  59. Analyzera1=newStandardAnalyzer(Version.LUCENE_35);
  60. //停用词分词器
  61. Analyzera2=newStopAnalyzer(Version.LUCENE_35);
  62. //简单分词器
  63. Analyzera3=newSimpleAnalyzer(Version.LUCENE_35);
  64. //空格分词器
  65. Analyzera4=newWhitespaceAnalyzer(Version.LUCENE_35);
  66. Stringtxt="我来自云南昭通昭阳区师专";
  67. AnalyzerUtils.displayToken(txt,a1);
  68. //[我][来][自][云][南][昭][通][昭][阳][区][师][专]
  69. AnalyzerUtils.displayToken(txt,a2);
  70. //[我来自云南昭通昭阳区师专]
  71. AnalyzerUtils.displayToken(txt,a3);
  72. //[我来自云南昭通昭阳区师专]
  73. AnalyzerUtils.displayToken(txt,a4);
  74. //[我来自云南昭通昭阳区师专]
  75. }
  76. /**
  77. *打印分词的详细信息
  78. */
  79. @Test
  80. publicvoidtest03(){
  81. //标准分词器
  82. Analyzera1=newStandardAnalyzer(Version.LUCENE_35);
  83. //停用词分词器
  84. Analyzera2=newStopAnalyzer(Version.LUCENE_35);
  85. //简单分词器
  86. Analyzera3=newSimpleAnalyzer(Version.LUCENE_35);
  87. //空格分词器
  88. Analyzera4=newWhitespaceAnalyzer(Version.LUCENE_35);
  89. Stringtxt="howareyouthankyou";
  90. AnalyzerUtils.displayAllToken(txt,a1);
  91. AnalyzerUtils.displayAllToken(txt,a2);
  92. AnalyzerUtils.displayAllToken(txt,a3);
  93. AnalyzerUtils.displayAllToken(txt,a4);
  94. }
  95. /**
  96. *停用词的测试
  97. */
  98. @Test
  99. publicvoidtest04(){
  100. Analyzera1=newMyStopAnalyzer(newString[]{"I","you","hate"});
  101. Analyzera2=newStopAnalyzer(Version.LUCENE_35);
  102. Stringtxt="howareYouthAnk'syouIhateyou";
  103. AnalyzerUtils.displayToken(txt,a1);
  104. AnalyzerUtils.displayToken(txt,a2);
  105. }
  106. /**
  107. *中文分词测试
  108. *使用词库分词,自己可扩展词库
  109. */
  110. @Test
  111. publicvoidtest05(){
  112. //Analyzera1=newMMSegAnalyzer();//未加入该分词器自带的词库
  113. //[我][来][自][云][南][昭][通][昭][阳][区][师][专]
  114. //导入分词的词典便有词库
  115. Analyzera1=newMMSegAnalyzer(newFile("D:\\Workspaces\\03_lucene_analyzer\\mmseg4j-1.8.4\\data"));
  116. //[我][来自][云南][昭][通][昭][阳][区][师专]
  117. //可以在data文件下面的words-my.dic扩展自己的词典,比如加了昭通,分词结果为:
  118. //[我][来自][云南][昭通][昭][阳][区][师专]
  119. Stringtxt="我来自云南昭通昭阳区师专";
  120. AnalyzerUtils.displayToken(txt,a1);
  121. }
  122. /**
  123. *同义词测试
  124. *@throwsIOException
  125. *@throwsCorruptIndexException
  126. */
  127. @Test
  128. publicvoidtest06()throwsCorruptIndexException,IOException{
  129. Analyzera1=newMySameAnalyzer();
  130. Stringtxt="我来自中国云南昭通昭阳区师专";
  131. AnalyzerUtils.displayAllToken(txt,a1);
  132. Stringkeyword="俺";
  133. Directorydire=newRAMDirectory();
  134. IndexWriterindexWriter=newIndexWriter(dire,newIndexWriterConfig(Version.LUCENE_35,a1));
  135. Documentdoc=newDocument();
  136. doc.add(newField("content",txt,Field.Store.YES,Field.Index.ANALYZED));
  137. indexWriter.addDocument(doc);
  138. indexWriter.close();
  139. IndexSearchersearch=newIndexSearcher(IndexReader.open(dire));
  140. TopDocstopDoc=search.search(newTermQuery(newTerm("content",keyword)),10);
  141. ScoreDoc[]scoreDoc=topDoc.scoreDocs;
  142. for(ScoreDocscore:scoreDoc){
  143. Documentdoc1=search.doc(score.doc);
  144. System.out.println(doc1.get("content"));
  145. }
  146. }
  147. }

5、扩展自己的停用词分词器
  1. packageorg.lucene.util;
  2. importjava.io.IOException;
  3. importjava.io.Reader;
  4. importjava.util.Set;
  5. importorg.apache.lucene.analysis.Analyzer;
  6. importorg.apache.lucene.analysis.LetterTokenizer;
  7. importorg.apache.lucene.analysis.LowerCaseFilter;
  8. importorg.apache.lucene.analysis.StopAnalyzer;
  9. importorg.apache.lucene.analysis.StopFilter;
  10. importorg.apache.lucene.analysis.TokenStream;
  11. importorg.apache.lucene.analysis.Tokenizer;
  12. importorg.apache.lucene.analysis.tokenattributes.CharTermAttribute;
  13. importorg.apache.lucene.util.Version;
  14. /**
  15. *扩展自己的停用词分词器
  16. *@authoruser
  17. *
  18. */
  19. publicclassMyStopAnalyzerextendsAnalyzer{
  20. privateSetstops;
  21. publicMyStopAnalyzer(String[]sws){
  22. //会自动将字符串数组转化为Set
  23. stops=StopFilter.makeStopSet(Version.LUCENE_35,sws,true);
  24. //把原来的停用词给加进来
  25. stops.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);
  26. }
  27. publicMyStopAnalyzer(){
  28. //获取原有的停用词
  29. stops.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);
  30. }
  31. @Override
  32. publicTokenStreamtokenStream(StringfieldName,Readerreader){
  33. System.out.println("//------------------------------------");
  34. Tokenizertokenizer=newLetterTokenizer(Version.LUCENE_35,reader);
  35. //Tokenizertokenizer=newStandardTokenizer(Version.LUCENE_35,reader);
  36. CharTermAttributecta=tokenizer.addAttribute(CharTermAttribute.class);
  37. try{
  38. while(tokenizer.incrementToken()){
  39. System.out.println(cta);
  40. }
  41. }catch(IOExceptione){
  42. e.printStackTrace();
  43. }
  44. System.out.println("------------------------------------\\");
  45. //为这个分词器设定过滤链和Tokenizer
  46. returnnewStopFilter(Version.LUCENE_35,
  47. newLowerCaseFilter(Version.LUCENE_35,
  48. newLetterTokenizer(Version.LUCENE_35,reader)),
  49. stops);
  50. }
  51. }
6、分词器的扩展,同义词分词器
  1. packageorg.lucene.util;
  2. importjava.io.Reader;
  3. importorg.apache.lucene.analysis.Analyzer;
  4. importorg.apache.lucene.analysis.TokenStream;
  5. importcom.chenlb.mmseg4j.Dictionary;
  6. importcom.chenlb.mmseg4j.MaxWordSeg;
  7. importcom.chenlb.mmseg4j.analysis.MMSegTokenizer;
  8. /**
  9. *分词器的扩展,同义词分词器
  10. *@authoruser
  11. *
  12. */
  13. publicclassMySameAnalyzerextendsAnalyzer{
  14. @Override
  15. publicTokenStreamtokenStream(StringfieldName,Readerreader){
  16. Dictionarydic=Dictionary.getInstance("D:\\Workspaces\\03_lucene_analyzer\\mmseg4j-1.8.4\\data");
  17. returnnewMySameTokenFilter(newMMSegTokenizer(newMaxWordSeg(dic),reader));
  18. }
  19. }

7、同义词过滤器的扩展
  1. packageorg.lucene.util;
  2. importjava.io.IOException;
  3. importjava.util.HashMap;
  4. importjava.util.Map;
  5. importjava.util.Stack;
  6. importorg.apache.lucene.analysis.TokenFilter;
  7. importorg.apache.lucene.analysis.TokenStream;
  8. importorg.apache.lucene.analysis.tokenattributes.CharTermAttribute;
  9. importorg.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
  10. importorg.apache.lucene.util.AttributeSource;
  11. /**
  12. *同义词过滤器的扩展
  13. *@authoruser
  14. *
  15. */
  16. publicclassMySameTokenFilterextendsTokenFilter{
  17. privateCharTermAttributecta=null;
  18. privatePositionIncrementAttributepia=null;
  19. privateAttributeSource.Statecurrent=null;
  20. privateStack<String>sames=null;
  21. protectedMySameTokenFilter(TokenStreaminput){
  22. super(input);
  23. cta=this.addAttribute(CharTermAttribute.class);
  24. pia=this.addAttribute(PositionIncrementAttribute.class);
  25. sames=newStack<String>();
  26. }
  27. /**
  28. *思想如下:
  29. *其实每个同义词都要放在CharTermAttribute里面,但是如果直接cta.append("大陆");的话
  30. *那会直接把原来的词和同义词连接在同一个语汇单元里面[中国大陆],这样是不行的
  31. *要的是这样的效果[中国][大陆]
  32. *那么就要在遇到同义词的时候把当前的状态保存一份,并把同义词的数组放入栈中,
  33. *这样在下一个语汇单元的时候判断同义词数组是否为空,不为空的话把之前的保存的一份状态
  34. *还原,然后在修改之前状态的值cta.setEmpty(),然后在把同义词的值加入cta.append("大陆")
  35. *再把位置增量设为0,pia.setPositionIncrement(0),这样的话就表示是同义词,
  36. *接着把该同义词的语汇单元返回
  37. */
  38. @Override
  39. publicbooleanincrementToken()throwsIOException{
  40. while(sames.size()>0){
  41. //将元素出栈,并获取这个同义词
  42. Stringstr=sames.pop();
  43. //还原状态
  44. restoreState(current);
  45. cta.setEmpty();
  46. cta.append(str);
  47. //设置位置
  48. pia.setPositionIncrement(0);
  49. returntrue;
  50. }
  51. if(!input.incrementToken())returnfalse;
  52. if(getSameWords(cta.toString())){
  53. //如果有同义词将当前状态先保存
  54. current=captureState();
  55. }
  56. returntrue;
  57. }
  58. /*
  59. *使用这种方式是不行的,这种会把的结果是[中国]替换成了[大陆]
  60. *而不是变成了[中国][大陆]
  61. @Override
  62. publicbooleanincrementToken()throwsIOException{
  63. if(!input.incrementToken())returnfalse;
  64. if(cta.toString().equals("中国")){
  65. cta.setEmpty();
  66. cta.append("大陆");
  67. }
  68. returntrue;
  69. }
  70. */
  71. privatebooleangetSameWords(Stringname){
  72. Map<String,String[]>maps=newHashMap<String,String[]>();
  73. maps.put("中国",newString[]{"大陆","天朝"});
  74. maps.put("我",newString[]{"咱","俺"});
  75. String[]sws=maps.get(name);
  76. if(sws!=null){
  77. for(Strings:sws){
  78. sames.push(s);
  79. }
  80. returntrue;
  81. }
  82. returnfalse;
  83. }
  84. }

8、打印语汇单元的信息
  1. packageorg.lucene.util;
  2. importjava.io.IOException;
  3. importjava.io.StringReader;
  4. importorg.apache.lucene.analysis.Analyzer;
  5. importorg.apache.lucene.analysis.TokenStream;
  6. importorg.apache.lucene.analysis.tokenattributes.CharTermAttribute;
  7. importorg.apache.lucene.analysis.tokenattributes.OffsetAttribute;
  8. importorg.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
  9. importorg.apache.lucene.analysis.tokenattributes.TypeAttribute;
  10. /**
  11. *打印语汇单元的信息
  12. *@authoruser
  13. *
  14. */
  15. publicclassAnalyzerUtils{
  16. publicstaticvoiddisplayToken(Stringstr,Analyzera){
  17. TokenStreamstream=a.tokenStream("content",newStringReader(str));
  18. /*
  19. *TokenStream相当于一条流
  20. *CharTermAttribute相当于一个碗
  21. *然后把碗丢进流里面,当碗得到一个元素后,碗又会自动流到了下
  22. *一个元素进行取值
  23. *这是一种设计模式:创建一个属性,这个属性会添加流中,
  24. *随着这个TokenStream增加
  25. */
  26. CharTermAttributecta=stream.addAttribute(CharTermAttribute.class);
  27. try{
  28. while(stream.incrementToken()){
  29. System.out.print("["+cta+"]");
  30. //System.out.println(stream);
  31. //如果直接打印Stream的话,toString打印如下:
  32. //(来,startOffset=1,endOffset=2,positionIncrement=1,type=<IDEOGRAPHIC>)
  33. }
  34. System.out.println();
  35. }catch(IOExceptione){
  36. e.printStackTrace();
  37. }
  38. }
  39. /**
  40. *打印详细信息的语汇单元
  41. *@paramstr
  42. *@parama
  43. */
  44. publicstaticvoiddisplayAllToken(Stringstr,Analyzera){
  45. TokenStreamstream=a.tokenStream("content",newStringReader(str));
  46. //位置增量
  47. PositionIncrementAttributepia=stream.addAttribute(PositionIncrementAttribute.class);
  48. //偏移量
  49. OffsetAttributeoa=stream.addAttribute(OffsetAttribute.class);
  50. //词元
  51. CharTermAttributecta=stream.addAttribute(CharTermAttribute.class);
  52. //分词的类型
  53. TypeAttributeta=stream.addAttribute(TypeAttribute.class);
  54. try{
  55. while(stream.incrementToken()){
  56. System.out.print(pia.getPositionIncrement()+":");
  57. System.out.print(cta+"["+oa.startOffset()+"-"+
  58. oa.endOffset()+"-"+ta.type());
  59. System.out.println();
  60. }
  61. System.out.println();
  62. }catch(IOExceptione){
  63. e.printStackTrace();
  64. }
  65. }
  66. }

工程下载路径: http://download.youkuaiyun.com/detail/wxwzy738/5284705
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值