`
lxwt909
  • 浏览: 570786 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多

      同义词功能在全文搜索时的意义,大家应该都懂的。今天中文我就试着写了一个同义词分词的示例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随书源码百度网盘下载地址

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

      

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

 

 

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

或者加裙
一起交流学习!

 

1
0
分享到:
评论
2 楼 小礼挥蕉 2015-11-24  
这篇确实完全没看懂,估计段位不够,学习了以后再回来看看
1 楼 oaibf 2015-05-27  
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class); 
        PositionIncrementAttribute positionIncrementAttribute = tokenStream.addAttribute(PositionIncrementAttribute.class); 
        CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class); 

不认识的类太多 迷茫

相关推荐

    lucene5.5做同义词分析器

    例如,以下是一个简单的示例代码片段,展示了如何构建一个同义词分析器: ```java public class SynonymAnalyzer extends Analyzer { private WordList wordList; public SynonymAnalyzer(Reader reader) throws...

    盘古分词、lucene3.0.3搜索的使用示例v1.3.zip

    在实际项目中,开发者可以根据业务需求进一步优化搜索算法,提升用户体验,比如添加同义词处理、模糊匹配、拼音搜索等功能。总的来说,盘古分词与Lucene的结合使用,为.NET开发者提供了一套强大的文本处理和搜索工具...

    es安装ik分词器

    ### Elasticsearch 安装 IK 分词器详解 #### 一、背景及需求分析 Elasticsearch 是一款基于 Lucene 的搜索引擎,广泛应用于日志处理、全文检索等场景。它提供了多种内置分词器来处理文本数据,但在实际应用过程中...

    Lucene如何使用TokenFilter进行再分词

    这只是一个简单的例子,实际上`TokenFilter`可以实现更复杂的功能,如词形还原、同义词替换等。 在提供的源代码中,你可能看到了更多关于如何实际应用`TokenFilter`的例子,包括如何组合多个`TokenFilter`以及如何...

    solr分词器使用手册

    在查询时,除了相同的分词及过滤过程外,还会额外使用SynonymFilterFactory来处理同义词。 #### 五、Solr安装与配置 - **下载与安装**: - **下载地址**:官方下载地址为http://lucene.apache.org/solr/。 - **...

    ik分词器文档

    - 这些文件通常包括但不限于`stopwords.txt`(停用词列表)、`synonyms.txt`(同义词列表)等。 3. **配置schema.xml**: - 在`schema.xml`文件中,配置`text_general`字段类型时,应使用IKAnalyzer作为分析器。 ...

    lucene5.4 + IKAnalyzer

    在描述中提到,这个版本的IK Analyzer已经支持同义词、停用词和扩展词,这意味着它可以识别并处理这些词汇的不同形式,从而提供更丰富的搜索结果。 **同义词支持** 同义词功能在信息检索中至关重要,因为用户可能会...

    lucene学习笔记

    同时,随着自然语言处理技术的发展,Lucene也在不断演进,支持更智能的搜索体验,例如模糊搜索、近似搜索、同义词搜索等。 总之,Lucene作为一款强大的全文检索工具,其学习和应用价值不言而喻。通过深入理解其核心...

    lucene in action 电子版

    - **分析器**:深入讲解了Lucene中的分析器组件,包括分词器、过滤器等,以及如何定制化分析流程以满足特定需求。 - **高级分析技巧**:介绍了如何通过组合不同的分析器来提高搜索质量,例如去除停用词、进行词干...

    lucene检索新闻数据演示

    【标题】"lucene检索新闻数据演示...学习和实践这个示例,可以深入理解Lucene的工作原理,提高全文检索的技能,同时对网页数据的处理和分析也有一定帮助。这在信息检索、大数据分析、内容推荐等领域有着广泛的应用。

    lucene的实际应用案例

    例如,标题可能需要更严格的分析,而正文可能允许更多的同义词。 3. **分词与分析**: 分词器将文本分解为单独的词语,然后分析器进一步处理这些词语,去除停用词、进行词形还原等,以提高搜索效果。 4. **索引构建...

    lucene-3.6.2.tgz

    - **扩展性**:允许开发者自定义分词器、过滤器和查询解析器,以适应特定业务需求。 5. **优化与性能** - **内存管理**:3.6.2版本对内存使用进行了优化,降低了对系统资源的需求。 - **查询性能**:通过查询...

    用lucene实现摘要的高亮点

    在提供的代码示例中,可以看到创建了一个`ExtractDigest`类,该类使用了ThesaurusAnalyzer,这是一个扩展的Analyzer,可能包含了对同义词或其他词汇关系的处理。`createIndex`方法用于建立索引,`analyzer`对象负责...

    lucene的封装和性能优化

    同时,对查询语句进行预处理,如关键词过滤、同义词扩展等,可以有效提高查询性能。 ### 4. 封装示例代码 ```java public class IndexManager { public void addDocument(Document doc) {...} public void ...

    Lucene基于java的全文检索案例

    索引过程包括分词(Tokenization)、词干提取(Stemming)、同义词处理(Synonym Handling)以及创建倒排索引(Inverted Index)等步骤。 2. **文档(Documents)**: 在 Lucene 中,文档是一个逻辑单元,包含一组...

    Lucene相关资料

    - **全文检索**:Lucene的核心功能是实现对文本数据的全文检索,即不仅根据关键字匹配,还能识别同义词、近义词等。 - **索引**:Lucene通过建立倒排索引,实现了快速的查询性能。倒排索引将文档中的每个词映射到...

    lucene_in_action中文版

    作者详细解释了如何处理停用词、同义词,以及如何利用正则表达式和自定义规则进行文本预处理。 搜索功能是Lucene的核心,书中详述了如何构建查询、执行高级查询语法、实现排序和过滤。此外,还涵盖了相关性调整、...

    Lucene in Action 2nd Edition MEAP Jun 2010

    - **简单示例**:通过构建一个简单的索引和搜索应用程序,让读者能够快速上手并体验Lucene的强大功能。 **2. 构建搜索索引** - **字段类型**:详细解释了Lucene中的各种字段类型,如存储字段(Stored Fields)、索引...

    分词查询XML

    在实际应用中,分词查询XML可能会结合数据库系统,例如使用Lucene、Elasticsearch等全文搜索引擎,或者自定义实现。这些系统不仅支持XML数据的索引和查询,还提供丰富的查询语法和性能优化手段。 标签“源码”和...

Global site tag (gtag.js) - Google Analytics