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

标签: lucene lucene 定义 | 发表时间:2014-02-06 11:41 | 作者:RangerWolf
出处:http://www.iteye.com

代码主要来源: 《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的词组进行同义词~



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [lucene lucene 定义] 推荐:

Lucene(3.5)自定义QueryParser

- - zzm
//  content: 全国软件专业人才设计与开发大赛  . //  Lucene实战(第二版) Lucene in action  .     private static final Analyzer analyzer = new StandardAnalyzer(version);//和索引时用的分词器一致  .

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

- - 行业应用 - ITeye博客
代码主要来源: 《Collective Intelligence 实战》. Lucene版本: 4.6.1. 原来的代码是基于2.2写的,很多东西已经变了. // 创建一系列的分词过滤器. // TokenStream的包装类 在2.2之中 是TokenStream. // 将数组转成lucene可识别的CharArraySet对象 CharArraySet类似java.util.set.

lucene排序

- - 开源软件 - ITeye博客
排序是对于全文检索来言是一个必不可少的功能,在实际运用中,排序功能能在某些时候给我们带来很大的方便,比如在淘宝,京东等一些电商网站我们可能通过排序来快速找到价格最便宜的商品,或者通过排序来找到评论数最高或卖的最好的商品,再比如在Iteye里的博客栏里,每天都会以降序的方式,来显示出最新发出的几篇博客,有了排序,我们就能在某些时候很方便快速的得到某些有效信息,所以说排序功能,无处不在 ^_^.

[原]Lucene系列-facet

- - 文武天下
facet:面、切面、方面. 个人理解就是维度,在满足query的前提下,观察结果在各维度上的分布(一个维度下各子类的数目). 如jd上搜“手机”,得到4009个商品. 其中品牌、网络、价格就是商品的维度(facet),点击某个品牌或者网络,获取更细分的结果. 点击品牌小米,获得小米手机的结果,显示27个.

[原]Lucene系列-FieldCache

- - 文武天下
域缓存,加载所有文档中某个特定域的值到内存,便于随机存取该域值. 当用户需要访问各文档中某个域的值时,IndexSearcher.doc(docId)获得Document的所有域值,但访问速度比较慢,而且只能获得Stored域的值. FieldCache能获得域值数组,根据docId random access域值.

Lucene 使用教程

- - 行业应用 - ITeye博客
1 lucene简介 . 1.1 什么是lucene . Lucene是一个全文搜索框架,而不是应用产品. 因此它并不像 http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实现这些产品. 1.2 lucene能做什么 . 要回答这个问题,先要了解lucene的本质.

Lucene 4.x 之 IndexReader

- - zzm
在Lucene 3.x时代,《Lucene In Action》是一本相当不错的参考书,书中详细介绍了Lucene各种高级使用技术,对于开发者来说非常实用. 但是近期Lucene升级到了4.x版本,在性能等各方面有了很大的提高,值得在新项目中使用. 然而Lucene 4.x中的API相比3.x来说有了很大的改变,《Lucene In Action》中的很多内容都已经过时了,并且由于4.x推出的时间不长,还没有比较好的文档来对用法进行说明,这个系列文章就是想记录下自己使用Lucene 4.x的经验体会,供大家参考使用.

文章: 集成Lucene和HBase

- - InfoQ cn
在所有先进的应用程序中,不管是购物站点还是社交网络乃至风景名胜站点,搜索都扮演着关键的角色. Lucene搜索程序库事实上已经成为实现搜索引擎的标准. 苹果、IBM、Attlassian(Jira)、Wolfram以及很多大家喜欢的公司【1】都使用了这种技术. 因此,大家对任何能够提升Lucene的可伸缩性和性能的实现都很感兴趣.

Solr\Lucene优劣势分析

- - 淘宝网综合业务平台团队博客
最早lucene2.4以及以前,追溯到2008年前后,lucene刚刚引起大家的关注,到后来Nutch. 、solr的出现,lucene变得更加热. Nutch、Solr的发展,极大推动了lucene的升级. 对于一些接触过搜索,使用过lucene、solr的人来说,一般都会感觉lucene、solr很牛逼.