Lucene5学习之自定义同义词分词器简单示例

  同义词功能在全文搜索时的意义,大家应该都懂的。今天中文我就试着写了一个同义词分词的示例demo,其实主要代码还是参考Lucene in Action 这本英文版书籍的随书代码,只不过Lucenen in Action书里的示例代码目前最新版只支持到Lucene4.x,对于Lucene5.x,代码需要稍作修改,下面是基于Lucene5.x的自定义同义词分词器demo:

 

Java代码  

  1. package com.yida.framework.lucene5.analyzer.synonym;  
  2.   
  3. import java.io.IOException;  
  4. /** 
  5.  * 同义词提取引擎 
  6.  * @author Lanxiaowei 
  7.  * 
  8.  */  
  9. public interface SynonymEngine {  
  10.     String[] getSynonyms(String s) throws IOException;  
  11. }  

 

Java代码  

  1. package com.yida.framework.lucene5.analyzer.synonym;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.HashMap;  
  5.   
  6. public class BaseSynonymEngine implements SynonymEngine {  
  7.     private static HashMap<String, String[]> map = new HashMap<String, String[]>();  
  8.       
  9.     {  
  10.         map.put("quick", new String[] {"fast","speedy"});  
  11.         map.put("jumps", new String[] {"leaps","hops"});  
  12.         map.put("over", new String[] {"above"});  
  13.         map.put("lazy", new String[] {"apathetic","slugish"});  
  14.         map.put("dog", new String[] {"canine","pooch"});  
  15.     }  
  16.   
  17.     public String[] getSynonyms(String s) throws IOException {  
  18.         return map.get(s);  
  19.     }  
  20. }  

 

Java代码  

  1. package com.yida.framework.lucene5.analyzer.synonym;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Stack;  
  5.   
  6. import org.apache.lucene.analysis.TokenFilter;  
  7. import org.apache.lucene.analysis.TokenStream;  
  8. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;  
  9. import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;  
  10. import org.apache.lucene.util.AttributeSource;  
  11.   
  12. /** 
  13.  * 自定义同义词过滤器 
  14.  *  
  15.  * @author Lanxiaowei 
  16.  *  
  17.  */  
  18. public class SynonymFilter extends TokenFilter {  
  19.     public static final String TOKEN_TYPE_SYNONYM = "SYNONYM";  
  20.   
  21.     private Stack<String> synonymStack;  
  22.     private SynonymEngine engine;  
  23.     private AttributeSource.State current;  
  24.   
  25.     private final CharTermAttribute termAtt;  
  26.     private final PositionIncrementAttribute posIncrAtt;  
  27.   
  28.     public SynonymFilter(TokenStream in, SynonymEngine engine) {  
  29.         super(in);  
  30.         synonymStack = new Stack<String>(); // #1  
  31.         this.engine = engine;  
  32.   
  33.         this.termAtt = addAttribute(CharTermAttribute.class);  
  34.         this.posIncrAtt = addAttribute(PositionIncrementAttribute.class);  
  35.     }  
  36.   
  37.     public boolean incrementToken() throws IOException {  
  38.         if (synonymStack.size() > 0) { // #2  
  39.             String syn = synonymStack.pop(); // #2  
  40.             restoreState(current); // #2  
  41.             // 这里Lucene4.x的写法  
  42.             // termAtt.setTermBuffer(syn);  
  43.   
  44.             // 这是Lucene5.x的写法  
  45.             termAtt.copyBuffer(syn.toCharArray(), 0, syn.length());  
  46.             posIncrAtt.setPositionIncrement(0); // #3  
  47.             return true;  
  48.         }  
  49.   
  50.         if (!input.incrementToken()) // #4  
  51.             return false;  
  52.   
  53.         if (addAliasesToStack()) { // #5  
  54.             current = captureState(); // #6  
  55.         }  
  56.   
  57.         return true; // #7  
  58.     }  
  59.   
  60.     private boolean addAliasesToStack() throws IOException {  
  61.         // 这里Lucene4.x的写法  
  62.         // String[] synonyms = engine.getSynonyms(termAtt.term()); //#8  
  63.   
  64.         // 这里Lucene5.x的写法  
  65.         String[] synonyms = engine.getSynonyms(termAtt.toString()); // #8  
  66.   
  67.         if (synonyms == null) {  
  68.             return false;  
  69.         }  
  70.         for (String synonym : synonyms) { // #9  
  71.             synonymStack.push(synonym);  
  72.         }  
  73.         return true;  
  74.     }  
  75. }  
  76.   
  77. /* 
  78. #1 Define synonym buffer 
  79. #2 Pop buffered synonyms 
  80. #3 Set position increment to 0 
  81. #4 Read next token 
  82. #5 Push synonyms onto stack 
  83. #6 Save current token 
  84. #7 Return current token 
  85. #8 Retrieve synonyms 
  86. #9 Push synonyms onto stack 
  87. */  

 

Java代码  

  1. package com.yida.framework.lucene5.analyzer.synonym;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.Reader;  
  5. import java.io.StringReader;  
  6.   
  7. import org.apache.lucene.analysis.Analyzer;  
  8. import org.apache.lucene.analysis.TokenStream;  
  9. import org.apache.lucene.analysis.Tokenizer;  
  10. import org.apache.lucene.analysis.Analyzer.TokenStreamComponents;  
  11. import org.apache.lucene.analysis.core.LetterTokenizer;  
  12. import org.apache.lucene.analysis.core.LowerCaseFilter;  
  13. import org.apache.lucene.analysis.core.StopAnalyzer;  
  14. import org.apache.lucene.analysis.core.StopFilter;  
  15. import org.apache.lucene.analysis.standard.StandardFilter;  
  16. import org.apache.lucene.analysis.standard.StandardTokenizer;  
  17.   
  18. import com.yida.framework.lucene5.util.analyzer.codec.MetaphoneReplacementFilter;  
  19.   
  20. /** 
  21.  * 自定义同义词分词器 
  22.  *  
  23.  * @author Lanxiaowei 
  24.  * @createTime 2015-03-31 10:15:23 
  25.  */  
  26. public class SynonymAnalyzer extends Analyzer {  
  27.   
  28.     private SynonymEngine engine;  
  29.   
  30.     public SynonymAnalyzer(SynonymEngine engine) {  
  31.         this.engine = engine;  
  32.     }  
  33.   
  34.     @Override  
  35.     protected TokenStreamComponents createComponents(String text) {  
  36.         Tokenizer tokenizer = new StandardTokenizer();  
  37.         TokenStream tokenStream = new SynonymFilter(tokenizer, engine);  
  38.         tokenStream = new LowerCaseFilter(tokenStream);  
  39.         tokenStream = new StopFilter(tokenStream,StopAnalyzer.ENGLISH_STOP_WORDS_SET);  
  40.         return new TokenStreamComponents(tokenizer, tokenStream);  
  41.     }  
  42. }  

 

Java代码  

  1. package com.yida.framework.lucene5.analyzer.synonym;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.analysis.Analyzer;  
  6.   
  7. import com.yida.framework.lucene5.util.AnalyzerUtils;  
  8.   
  9. public class SynonymAnalyzerTest {  
  10.     public static void main(String[] args) throws IOException {  
  11.         String text = "The quick brown fox jumps over the lazy dog";  
  12.         Analyzer analyzer = new SynonymAnalyzer(new BaseSynonymEngine());  
  13.         AnalyzerUtils.displayTokens(analyzer, text);  
  14.     }  
  15. }  

 

Java代码  

  1. package com.yida.framework.lucene5.util;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import junit.framework.Assert;  
  6.   
  7. import org.apache.lucene.analysis.Analyzer;  
  8. import org.apache.lucene.analysis.TokenStream;  
  9. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;  
  10. import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;  
  11. import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;  
  12. import org.apache.lucene.analysis.tokenattributes.TypeAttribute;  
  13.   
  14. /** 
  15.  * 用于分词器测试的一个简单工具类(用于打印分词情况,包括Term的起始位置和结束位置(即所谓的偏 * 移量),位置增量,Term字符串,Term字符串类型(字符串/阿拉伯数字之类的)) 
  16.  * @author Lanxiaowei 
  17.  * 
  18.  */  
  19. public class AnalyzerUtils {  
  20.     public static void displayTokens(Analyzer analyzer,String text) throws IOException {  
  21.         TokenStream tokenStream = analyzer.tokenStream("text", text);  
  22.         displayTokens(tokenStream);  
  23.     }  
  24.       
  25.     public static void displayTokens(TokenStream tokenStream) throws IOException {  
  26.         OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);  
  27.         PositionIncrementAttribute positionIncrementAttribute = tokenStream.addAttribute(PositionIncrementAttribute.class);  
  28.         CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);  
  29.         TypeAttribute typeAttribute = tokenStream.addAttribute(TypeAttribute.class);  
  30.           
  31.         tokenStream.reset();  
  32.         int position = 0;  
  33.         while (tokenStream.incrementToken()) {  
  34.             int increment = positionIncrementAttribute.getPositionIncrement();  
  35.             if(increment > 0) {  
  36.                 position = position + increment;  
  37.                 System.out.print(position + ":");  
  38.             }  
  39.             int startOffset = offsetAttribute.startOffset();  
  40.             int endOffset = offsetAttribute.endOffset();  
  41.             String term = charTermAttribute.toString();  
  42.             System.out.println("[" + term + "]" + ":(" + startOffset + "-->" + endOffset + "):" + typeAttribute.type());  
  43.         }  
  44.     }  
  45.       
  46.     /** 
  47.      * 断言分词结果 
  48.      * @param analyzer 
  49.      * @param text        源字符串 
  50.      * @param expecteds   期望分词后结果 
  51.      * @throws IOException  
  52.      */  
  53.     public static void assertAnalyzerTo(Analyzer analyzer,String text,String[] expecteds) throws IOException {  
  54.         TokenStream tokenStream = analyzer.tokenStream("text", text);  
  55.         CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);  
  56.         for(String expected : expecteds) {  
  57.             Assert.assertTrue(tokenStream.incrementToken());  
  58.             Assert.assertEquals(expected, charTermAttribute.toString());  
  59.         }  
  60.         Assert.assertFalse(tokenStream.incrementToken());  
  61.         tokenStream.close();  
  62.     }  
  63. }  

 以上代码都是Lucene in Action这本书里面的示例代码,我只不过是基于Lucene5.x把它重写并调试成功了,特此分享,希望对正在学习Lucene5的童鞋们有所帮助。demo代码我会在底下附件里上传,有需要demo源码的请自己在底下的附件里下载,Lucene in Action这本书的随书源码我已上传到我的百度网盘,也一并分享给大家,Lucene in Action随书源码百度网盘下载地址

       戳我,戳我,快戳我!!!Come on.

      

      千言万语都在代码中,就不多说了,打完收工!

 

 

如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,

或者加裙
一起交流学习!

转载:http://iamyida.iteye.com/blog/2197355

时间: 2025-01-26 14:55:28

Lucene5学习之自定义同义词分词器简单示例的相关文章

Lucene5学习之使用MMSeg4j分词器

     MMSeg4j是一款中文分词器,详细介绍如下:        1.mmseg4j 用 Chih-Hao Tsai 的 MMSeg 算法(http://technology.chtsai.org/mmseg/ )实现的中文分词器,并实现 lucene 的 analyzer 和 solr 的TokenizerFactory 以方便在Lucene和Solr中使用.          2.MMSeg 算法有两种分词方法:Simple和Complex,都是基于正向最大匹配.Complex 加了四

Lucene5学习之使用IKAnalyzer分词器

   之前的示例中,使用的是默认的StandardAnalyzer分词器,不能有效的进行中文分词,下面演示下如何在Lucene5.0中使用IKAnalyzer分词器.     首先下载IKAnalyzer分词器源码,IKAnalyzer分词器源码托管在OSChina的git上.下载地址: http://git.oschina.net/wltea/IK-Analyzer-2012FF 请如图下载IK的源代码:    然后打开Eclipse新建一个Java Project:      然后解压下载下

Lucene5学习之使用Ansj-seg分词器

    这回我们来玩玩ansj分词器,由于Lucene5.0在API上有点小变化,需要修改ansj分词器源码,重新打包jar包,然后mvn install到本地仓库才能引用到项目中.至于怎么修改以及怎么打包jar,我就不过多说明了,有点麻烦,我想偷个懒,哈哈.这里我就直接把打包后的jar分享给你们,jar包注意在底下的附件里下载.     我就说说,怎么在项目中使用ansj分词器,首先pom.xml引入ansj分词器的依赖.   Xml代码   <!-- ansj-seg -->   <

Lucene 3.6.2入门(5) 自定义停用词分词器和同义词分词器

首先是用于显示分词信息的HelloCustomAnalyzer.java package com.jadyer.lucene; import java.io.IOException; import java.io.StringReader; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.toke

Lucene5学习之自定义排序

         在Lucene5学习之排序-Sort中,我们已经学习了Sort的用法,已经了解了,Lucene搜索返回的命中结果默认是按照索引文档跟搜索关键字的相关度已经排序的,而相关度又是基于内部的打分机制和索引文档id,内部的打分机制则是根据Term的IDF-TF以及创建索引时Field的boost等决定的,默认是按照得分降序排序,得分相同再按docId升序排序.如果你觉得默认的排序方式满足不了你的需求,你可以设置SortField按照特定的域来排序,特定的域排序其实根据域的type类型去

JAVA学习Swing章节流布局管理器简单学习

package com.swing; import java.awt.Container; import java.awt.FlowLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.WindowConstants; /** * 1:流(FlowLayout)布局管理器是布局管理器中最基本的布局管理器,流布局管理器在整个容器中 * 的布局正如其名,像流一样从左到右摆放组件,直到占据了这

Lucene5学习之拼音搜索

     今天来说说拼音检索,这个功能其实还是用来提升用户体验的,别的不说,最起码避免了用户切换输入法,如果能支持中文汉语拼音简拼,那用户搜索时输入的字符更简便了,用户输入次数少了就是为了给用户使用时带来便利.来看看一些拼音搜索的经典案例:             看了上面几张图的功能演示,我想大家也应该知道了拼音检索的作用以及为什么要使用拼音检索了.那接下来就来说说如何实现:      首先我们我们需要把分词器分出来的中文词语转换为汉语拼音,Java中汉字转拼音可以使用pinyin4j这个类库

使用肖波的KTDictSeg分词器 为Lucene.net服务

最近在看Lucene.net 发现Lucene.net的中文分词资料不是很多,很早就在看肖波的KTDictSeg,觉的分词效果不错,但是没有lucene接口,看他的blog也是很长时间没有更新了 他在他的blog中提到将在下一个版本中提供对lucene的支持,我这里期待中...同时blog中提到一挥的修改版本,但是一挥的站打不开了,不知道什么原因,我刚刚看这个时间不长,查了些资料 写了下面的代码实现了KTDictSeg在Lucene.net中的调用,期待有更好的方法出现 下面附上代码 1usin

Lucene5学习之LuceneUtils工具类简单封装

     周六花了整整一下午,将Lucene5中有关索引的常见操作进行了简单封装,废话不多说,上代码:   Java代码   package com.yida.framework.lucene5.util;      import java.io.IOException;   import java.util.concurrent.ExecutorService;   import java.util.concurrent.locks.Lock;   import java.util.concu