同义词功能在全文搜索时的意义,大家应该都懂的。今天中文我就试着写了一个同义词分词的示例demo,其实主要代码还是参考Lucene in Action 这本英文版书籍的随书代码,只不过Lucenen in Action书里的示例代码目前最新版只支持到Lucene4.x,对于Lucene5.x,代码需要稍作修改,下面是基于Lucene5.x的自定义同义词分词器demo:
- package com.yida.framework.lucene5.analyzer.synonym;
- import java.io.IOException;
- /**
- * 同义词提取引擎
- * @author Lanxiaowei
- *
- */
- public interface SynonymEngine {
- String[] getSynonyms(String s) throws IOException;
- }
- package com.yida.framework.lucene5.analyzer.synonym;
- import java.io.IOException;
- import java.util.HashMap;
- public class BaseSynonymEngine implements SynonymEngine {
- private static HashMap<String, String[]> map = new HashMap<String, String[]>();
- {
- map.put("quick", new String[] {"fast","speedy"});
- map.put("jumps", new String[] {"leaps","hops"});
- map.put("over", new String[] {"above"});
- map.put("lazy", new String[] {"apathetic","slugish"});
- map.put("dog", new String[] {"canine","pooch"});
- }
- public String[] getSynonyms(String s) throws IOException {
- return map.get(s);
- }
- }
- package com.yida.framework.lucene5.analyzer.synonym;
- import java.io.IOException;
- import java.util.Stack;
- import org.apache.lucene.analysis.TokenFilter;
- import org.apache.lucene.analysis.TokenStream;
- import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
- import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
- import org.apache.lucene.util.AttributeSource;
- /**
- * 自定义同义词过滤器
- *
- * @author Lanxiaowei
- *
- */
- public class SynonymFilter extends TokenFilter {
- public static final String TOKEN_TYPE_SYNONYM = "SYNONYM";
- private Stack<String> synonymStack;
- private SynonymEngine engine;
- private AttributeSource.State current;
- private final CharTermAttribute termAtt;
- private final PositionIncrementAttribute posIncrAtt;
- public SynonymFilter(TokenStream in, SynonymEngine engine) {
- super(in);
- synonymStack = new Stack<String>(); // #1
- this.engine = engine;
- this.termAtt = addAttribute(CharTermAttribute.class);
- this.posIncrAtt = addAttribute(PositionIncrementAttribute.class);
- }
- public boolean incrementToken() throws IOException {
- if (synonymStack.size() > 0) { // #2
- String syn = synonymStack.pop(); // #2
- restoreState(current); // #2
- // 这里Lucene4.x的写法
- // termAtt.setTermBuffer(syn);
- // 这是Lucene5.x的写法
- termAtt.copyBuffer(syn.toCharArray(), 0, syn.length());
- posIncrAtt.setPositionIncrement(0); // #3
- return true;
- }
- if (!input.incrementToken()) // #4
- return false;
- if (addAliasesToStack()) { // #5
- current = captureState(); // #6
- }
- return true; // #7
- }
- private boolean addAliasesToStack() throws IOException {
- // 这里Lucene4.x的写法
- // String[] synonyms = engine.getSynonyms(termAtt.term()); //#8
- // 这里Lucene5.x的写法
- String[] synonyms = engine.getSynonyms(termAtt.toString()); // #8
- if (synonyms == null) {
- return false;
- }
- for (String synonym : synonyms) { // #9
- synonymStack.push(synonym);
- }
- return true;
- }
- }
- /*
- #1 Define synonym buffer
- #2 Pop buffered synonyms
- #3 Set position increment to 0
- #4 Read next token
- #5 Push synonyms onto stack
- #6 Save current token
- #7 Return current token
- #8 Retrieve synonyms
- #9 Push synonyms onto stack
- */
- package com.yida.framework.lucene5.analyzer.synonym;
- import java.io.BufferedReader;
- import java.io.Reader;
- import java.io.StringReader;
- import org.apache.lucene.analysis.Analyzer;
- import org.apache.lucene.analysis.TokenStream;
- import org.apache.lucene.analysis.Tokenizer;
- import org.apache.lucene.analysis.Analyzer.TokenStreamComponents;
- import org.apache.lucene.analysis.core.LetterTokenizer;
- import org.apache.lucene.analysis.core.LowerCaseFilter;
- import org.apache.lucene.analysis.core.StopAnalyzer;
- import org.apache.lucene.analysis.core.StopFilter;
- import org.apache.lucene.analysis.standard.StandardFilter;
- import org.apache.lucene.analysis.standard.StandardTokenizer;
- import com.yida.framework.lucene5.util.analyzer.codec.MetaphoneReplacementFilter;
- /**
- * 自定义同义词分词器
- *
- * @author Lanxiaowei
- * @createTime 2015-03-31 10:15:23
- */
- public class SynonymAnalyzer extends Analyzer {
- private SynonymEngine engine;
- public SynonymAnalyzer(SynonymEngine engine) {
- this.engine = engine;
- }
- @Override
- protected TokenStreamComponents createComponents(String text) {
- Tokenizer tokenizer = new StandardTokenizer();
- TokenStream tokenStream = new SynonymFilter(tokenizer, engine);
- tokenStream = new LowerCaseFilter(tokenStream);
- tokenStream = new StopFilter(tokenStream,StopAnalyzer.ENGLISH_STOP_WORDS_SET);
- return new TokenStreamComponents(tokenizer, tokenStream);
- }
- }
- package com.yida.framework.lucene5.analyzer.synonym;
- import java.io.IOException;
- import org.apache.lucene.analysis.Analyzer;
- import com.yida.framework.lucene5.util.AnalyzerUtils;
- public class SynonymAnalyzerTest {
- public static void main(String[] args) throws IOException {
- String text = "The quick brown fox jumps over the lazy dog";
- Analyzer analyzer = new SynonymAnalyzer(new BaseSynonymEngine());
- AnalyzerUtils.displayTokens(analyzer, text);
- }
- }
- package com.yida.framework.lucene5.util;
- import java.io.IOException;
- import junit.framework.Assert;
- import org.apache.lucene.analysis.Analyzer;
- import org.apache.lucene.analysis.TokenStream;
- import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
- import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
- import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
- import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
- /**
- * 用于分词器测试的一个简单工具类(用于打印分词情况,包括Term的起始位置和结束位置(即所谓的偏 * 移量),位置增量,Term字符串,Term字符串类型(字符串/阿拉伯数字之类的))
- * @author Lanxiaowei
- *
- */
- public class AnalyzerUtils {
- public static void displayTokens(Analyzer analyzer,String text) throws IOException {
- TokenStream tokenStream = analyzer.tokenStream("text", text);
- displayTokens(tokenStream);
- }
- public static void displayTokens(TokenStream tokenStream) throws IOException {
- OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
- PositionIncrementAttribute positionIncrementAttribute = tokenStream.addAttribute(PositionIncrementAttribute.class);
- CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
- TypeAttribute typeAttribute = tokenStream.addAttribute(TypeAttribute.class);
- tokenStream.reset();
- int position = 0;
- while (tokenStream.incrementToken()) {
- int increment = positionIncrementAttribute.getPositionIncrement();
- if(increment > 0) {
- position = position + increment;
- System.out.print(position + ":");
- }
- int startOffset = offsetAttribute.startOffset();
- int endOffset = offsetAttribute.endOffset();
- String term = charTermAttribute.toString();
- System.out.println("[" + term + "]" + ":(" + startOffset + "-->" + endOffset + "):" + typeAttribute.type());
- }
- }
- /**
- * 断言分词结果
- * @param analyzer
- * @param text 源字符串
- * @param expecteds 期望分词后结果
- * @throws IOException
- */
- public static void assertAnalyzerTo(Analyzer analyzer,String text,String[] expecteds) throws IOException {
- TokenStream tokenStream = analyzer.tokenStream("text", text);
- CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
- for(String expected : expecteds) {
- Assert.assertTrue(tokenStream.incrementToken());
- Assert.assertEquals(expected, charTermAttribute.toString());
- }
- Assert.assertFalse(tokenStream.incrementToken());
- tokenStream.close();
- }
- }
以上代码都是Lucene in Action这本书里面的示例代码,我只不过是基于Lucene5.x把它重写并调试成功了,特此分享,希望对正在学习Lucene5的童鞋们有所帮助。demo代码我会在底下附件里上传,有需要demo源码的请自己在底下的附件里下载,Lucene in Action这本书的随书源码我已上传到我的百度网盘,也一并分享给大家,Lucene in Action随书源码百度网盘下载地址:
千言万语都在代码中,就不多说了,打完收工!
如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,
或者加裙
一起交流学习!
转载:http://iamyida.iteye.com/blog/2197355
时间: 2025-01-26 14:55:28