全文检索技术与Lucene的使用


概念


在谈全文检索之前,首先让我们来了解一下什么是信息检索。信息检索就是从信息集合中找出与用户需求相关的信息。被检索的信息除了文本外,还有图像、音频、视频等多媒体信息,这里我们只讨论文本信息的检索。

全文检索是信息检索技术的一种,主要是把用户的查询请求和全文中的每一个词进行比较,不考虑查询请求与文本语义上的匹配。在信息检索工具中,全文检索是最具通用性和实用性的。


流程

  • 建立索引
搜索的目的是为了在大量的信息中发现自己感兴趣的信息。但是,当有了足够的资料(比如网页、Word文档、Pdf文档,或数据库中的资料等)之后,并不能立即开始搜索,而且随着大数据时代的到来,直接搜索浪费的时间是不可估算的,因此,在搜索之前,必须先对信息建立索引。

建立索引,就是对待搜索的信息进行一定的分析,并将分析结果安照一定的组织方式存储起来,通常将这些结果存储在文件中。存储分析结果的文件的集合就是索引。在查询时,先从索引中查找,由于索引是按照一定的结构组织的,所以查询的速度是非常快的。

为了提供检索的功能,信息检索系统会事先做一些准备工作,信息的采集与加工,流程如下。

全文检索技术与Lucene的使用_第1张图片

  • 数据分词
建立好索引之后,就需要分词器对文本资源进行切分,将文本按规则且分为一个个可以进行索引的最小单位,也就是所谓的关键词。例如,某文档中的一段文本,经过分词器分词之后,会成为如下的情况。

全文检索技术与Lucene的使用_第2张图片

需要注意的是,建立索引和进行搜索都是需要分词器进行分词的,而且,为了保证能正确的搜索到结果,在建立索引与进行搜索时使用的分词器应是同一个。

由于中英文的不同,分词器还分为 英文分词、中文分词以及停用词等。英文分词的主要流程是,输入文本 → 关键词切分 → 去除停用词 → 形态还原 → 转为小写 。其中,形态还原是去除单词词尾的形态变化,将其还原为词的原型,例如,worked → work,studies → study 。

中文的分词比较复杂,因为不是一个字就是一个词,而且一个词在另外一个地方就可能不是一个词,如在“帽子和服装”中,“和服”就不是一个词。对于中午分词,通常有三种方式,单字分词、二分法分词、词典分词。

有些词在文本中出现的频率是非常高的,而且对文本所携带的信息基本不产生影响,比如英文的“a、an、the、of”,或中文的“的、了、着”,以及各种标点符号等,这样的词称为停用词。文本经过分词之后,停用词通常被过滤掉,不会被进行索引。在检索的时候,用户的查询中如果含有停用词,检索系统也会将其过滤掉。这也给了我们一些启示,在检索的时候,尽量的排除停用词可以加快搜索的速度。

  • 倒排索引
倒排索引,索引对象是文档中的单词等,用来存储这些单词在一个文档中的位置。比如,有些书在最后提供的索引,就可以看成是一种倒排序索引。可以通过一些关键字,在全书中检索出与之相关的部分。

全文检索技术与Lucene的使用_第3张图片

词汇表规模相对较小,文档集合规模较大。进行检索时,先从检索词汇表开始,然后找到相对应的文档。如果查询中仅包含一个关键词,则在词汇表中找到该单词,并取出他对应的文档。如果包含多个关键词,则需要将各个单词检索出的记录进行合并。

维护倒排索引有三个操作,插入、删除和更新文档。但是更新操作需要较高的代价。因为文档修改后,就可能会造成文档中的很多的关键词的位置都发生了变化,这就需要频繁的读取和修改记录。因此,一般不进行更新操作,而是使用“先删除,后创建”的方式更新操作。


Lucene


Lucene 是一个高性能、可伸缩的全文检索工具包。你可以使用它建立索引和优化搜索能力。有很多应用程序使用Lucene 来提供全文检索的功能,比如开发人员常用的Eclipse的帮助子系统,就是使用Lucene实现的。


HelloWorld 程序


在开始做Demo之前,需要把Lucene的几个jar包加到项目中,需要的jar包有(这里用的是 lucene 2.4的版本)

全文检索技术与Lucene的使用_第4张图片

建立索引


/**
 * 创建索引
 * 
 * IndexWriter 是用来操作(增、删、改)索引库的
 */
@Test
public void createIndex() throws Exception {
	// file --> doc
	Document doc = File2DocumentUtils.file2Document(filePath);

	// 建立索引
	IndexWriter indexWriter = new IndexWriter(indexPath, analyzer, true,
			MaxFieldLength.LIMITED);
	indexWriter.addDocument(doc);
	indexWriter.close();
}


搜索


/**
 * 搜索
 * 
 * IndexSearcher 是用来在索引库中进行查询的
 */
@Test
public void search() throws Exception {
	String queryString = "document";

	// 1,把要搜索的文本解析为 Query
	String[] fields = { "name", "content" };
	QueryParser queryParser = new MultiFieldQueryParser(fields, analyzer);
	Query query = queryParser.parse(queryString);

	// 2,进行查询
	IndexSearcher indexSearcher = new IndexSearcher(indexPath);
	Filter filter = null;
	TopDocs topDocs = indexSearcher.search(query, filter, 10000);
	System.out.println("总共有【" + topDocs.totalHits + "】条匹配结果");

	// 3,打印结果
	for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
		int docSn = scoreDoc.doc; // 文档内部编号
		Document doc = indexSearcher.doc(docSn); // 根据编号取出相应的文档
		File2DocumentUtils.printDocumentInfo(doc); // 打印出文档信息
	}
}


结束语


随着大数据的来临,对数据的查询技术也面临着新的挑战,每每我们通过百度、Google 搜索我们需要的信息时,尽管互联网上与之相关的海量数据何其之多,但是他们总是能够很快的找到我们需要的信息。这就是对大数据的进行处理之后的结果,给我们提供了更快速的查询。然而,我们现在就需要这样的技术来处理我们日益繁多的数据,以方便我们随时对信息的需求。

在这个时代,只要掌握了数据,掌握了处理数据的能力,掌握了检索信息的用户体验,那么你距离进入福布斯富豪榜就不远了。小伙伴们,努力吧!

你可能感兴趣的:(【Java开发】)