`

[Lucene] 使用Lucene创建自定义的词干分析器

阅读更多

代码主要来源: 《Collective Intelligence 实战》

Lucene版本: 4.6.1

原来的代码是基于2.2写的,很多东西已经变了。现在用4.6.1重现实现一遍

 

 

package impl;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.core.LowerCaseFilter;
import org.apache.lucene.analysis.core.StopFilter;
import org.apache.lucene.analysis.en.PorterStemFilter;
import org.apache.lucene.analysis.standard.StandardTokenizer;
import org.apache.lucene.analysis.synonym.SynonymFilter;
import org.apache.lucene.analysis.synonym.SynonymMap;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.util.CharArraySet;
import org.apache.lucene.util.CharsRef;
import org.apache.lucene.util.Version;

public class PorterStemStopWordAnalyzer extends Analyzer {

	// 自定义停用词
	private static final String[] stopWords = {"and", "of", "the", "to", "is", "their", "can", "all"};
	public PorterStemStopWordAnalyzer() {
	}

	@Override
	protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
		// 创建一个分词器
		Tokenizer tokenizer = new StandardTokenizer(Version.LUCENE_46, reader);
		
		// 创建一系列的分词过滤器
		TokenFilter lowerCaseFilter = new LowerCaseFilter(Version.LUCENE_46, tokenizer);
		TokenFilter synonymFilter = new SynonymFilter(lowerCaseFilter, getSynonymMap(), true);
		TokenFilter stopFilter = new StopFilter(Version.LUCENE_46, synonymFilter, buildCharArraySetFromArry(stopWords));
		TokenFilter stemFilter = new PorterStemFilter(stopFilter);
		
		// TokenStream的包装类 在2.2之中 是TokenStream
		return new TokenStreamComponents(tokenizer, stemFilter);
	}
	
	// 将数组转成lucene可识别的CharArraySet对象 CharArraySet类似java.util.set
	private CharArraySet buildCharArraySetFromArry(String[] array) {
		CharArraySet set = new CharArraySet(Version.LUCENE_46, array.length, true);
		for(String value : array) {
			set.add(value);
		}
		return set;
	}
	
	// 创建一个同义词表
	private SynonymMap getSynonymMap() {
		String base1 = "fast";
		String syn1 = "rapid";
		
		String base2 = "slow";
		String syn2 = "sluggish";
		
		SynonymMap.Builder sb = new SynonymMap.Builder(true);
		sb.add(new CharsRef(base1), new CharsRef(syn1), true);
		sb.add(new CharsRef(base2), new CharsRef(syn2), true);
		SynonymMap smap = null;
		try {
			smap = sb.build();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return smap;
	}
	
	// 测试方法
	public static void testPorterStemmingAnalyzer() throws IOException {
		Analyzer analyzer = new PorterStemStopWordAnalyzer();
		String text = "Collective intelligence and Web2.0, fast and rapid";
		Reader reader = new StringReader(text);
		TokenStream ts = null;
		try {
			ts = analyzer.tokenStream(null, reader);
			ts.reset();
			while(ts.incrementToken()) {
				CharTermAttribute ta = ts.getAttribute(CharTermAttribute.class);  
				System.out.println(ta.toString());
			}
		} catch (IOException e) {
			e.printStackTrace();
		} 
		
	}
	
	public static void main(String[] args) throws IOException {
		testPorterStemmingAnalyzer();
	}

}

 

 

注意:

(1) TokenStream在初始化之后需要reset一次,不然会抛出异常

(2) 将TokenStream 转成Token 常用的一个方法就是使用CharTermAttribute

除了CharTermAttribute 还有其他的Attribute: 比如FlagsAttribute ...

(3) 使用到的类库可以参考上一篇文章:http://rangerwolf.iteye.com/admin/blogs/2011535

(4) 在createComponents方法之中使用了一个同义词过滤器,在构造这个过滤器的时候是通过getSynonymMap方法进行的。在测试样本之中的 fast and rapid 解析完成之后的结果如下:

fast
rapid
rapid

 相当于有两个rapid! 可能是因为这是因为synonymFilter在stopFilter之前运行。

根据java doc 文档的秒速,同义词过滤器应该尽早的运行。比如second rule.

做了另外的一个测试:

String base3 = "Collective Intelligence";
String syn3 = "CI";
sb.add(new CharsRef(base3), new CharsRef(syn3), true);

 即将Collective Intelligence 跟CI 同义

同样的样本的运行结果完全不变! 

说明无法对词长度为2的词组进行同义词~

分享到:
评论

相关推荐

    java lucene 实现分词和词干抽取

    用java实现的,利用了lucene里面的standardAnalyzer分析器实现的分词,可以去停用词,再利用波特算法实现 词干提取 最后排序 和词频统计输出

    Lucene+in+Action简体中文版1-4章

    4.1 使用分析器 分析(Analysis),在Lucene当中指的是将域(Field)文本转换为最基本的索引表示单元——项(Term)的过程。在搜索过程中,这些项用于决定什么样的文档能匹配查询条件。例如,如果这句话“For ...

    maoristemmer:te kupu reoMāori的Snowball stemmer,以及LuceneSolr SnowballPorterFilterFactory的派生类

    并将其包含在分析器库中,以便DSpace和其他使用用于搜索的Apache Solr可以为字段类型指定除英语和其他语言之外的毛利词干快速入门(Lucene库) 要在Apache Solr 4.10.4(例如DSpace 6)中测试此词干分析器,请执行...

    arirang.lucene-analyzer-5.0.0:Lucene 5.0.0 Arirang Hangul Stemetic Analyzer

    这是一个将Sumyung Lee创建的阿里郎韩语词素分析器应用到Lucene-5.0.0的项目。 阿里郎词干分析器咖啡厅: :

    Lucene-Analyzers---Comparision:测试不同的分析仪

    Lucene-Analyzers---比较测试不同的分析仪使用四个分析器为 AP89 生成 Lucene 索引 KeywordAnalyzer SimpleAnalyzer StopAnalyzer StandardAnalyzer 检查标记化,标记,词干,停用词去除,术语和其他观察

    lucene-solr-analysis-turkish:Apache LuceneSolr的土耳其语分析组件

    但是,该词干提取器性能较差,并且发生有趣的碰撞。 例如; ALTIN,ALIM,阿林,俺答,和alıntı都减少到相同的干。 换句话说,即使它们具有完全不同的含义,也将它们视为相同的词来对待。 我将在这里发布其他一些...

    elasticsearch-skroutz-greekstemmer:希腊语弹性搜索之声

    但是,此词干分析器仅捕获了158个,因为添加其余的后缀会降低词干分析器在用于其评估的单词集上的精度。 但是,将这些后缀排除在我们的包含超过120.000个单词的单词集上效果不佳。 因此,为了满足我们的需求,我们...

    minerva:计算机科学项目

    自定义分析器与SwedishAnalyzer 相同,但没有词干。 索引器用于从 bz2 文件创建索引的类,分为段落或整个 atricles 查询通道解析查询并检索所需数量的文档 密涅瓦该程序的核心包含用于查询、排名和重新排名的方法...

    estem:埃尔朗邮票(波兰票)

    Stempel(波兰语词干)适用于Erlang 许可证:用于绑定的Apache 2... 运行词干分析器 estem_java : stem ([<< " do " >>, << " wynajęcia " >>, << " przytulne " >>, << " bezczynszowe " >

    Information-Retrieval-News:信息检索系统

    应该使用哪些停用词删除,词干识别,短语识别和其他分析器? 是否可以使用更复杂的语言建模过程? 查询在任务一中,查询是简单的,预定义的短文本字符串。 但是,在许多TREC任务中,您将获得一个“主题”,而不是...

    akarata:印尼语词干分析器-JavaScript库从印尼语的逐字单词中提取基本单词

    Akarata是一个JavaScript库,用于从印度尼西亚语中带有首字母或结尾词缀的单词中提取词根/音节(词干)。 词根取自单词“ root”,因此发音时较短。 根源是根据Fadillah Z Tala在论文描述的算法,从基于Porter ...

    nlproc_sdk_sample_code:Lemmatizer and Sentiment Analysis SDK示例代码

    信息检索(我们为Lucene / Solr / Elasticsearch提供了令牌过滤器,如果需要,请与我们联系) 情绪分析(如果对此感兴趣,请继续阅读) 机器翻译:为避免稀疏词形空间的问题,可以在翻译之前先对其进行词形化 您...

    The Charabia Normalizer-开源

    用Java编写的基于上下文的基于规则的文本标准化引擎,可用于实现词干算法或语音标准化器。 该项目包括一个法语词干/语音标准化器和一个soundex实现。 包括Lucene分析仪

Global site tag (gtag.js) - Google Analytics