(转载)
使用Lucene的API遍历Lucene索引
一般使用Lucene的人都很少需要对索引进行遍历之类的操作,因为使用Lucene一般都不会对其索引文件产生太大兴趣,只注重将Lucene作为一个
全文检索工具来使用而已,并不在意其内部实现和结构。但是很多学习Lucene的朋友都希望可以看见完整的Lucene索引内容,至少包含索引词、索引词
出现的文档、索引词在文档中的位置(这里指的位置并不是词在原文中的位置,而是指其在Lucene对文档进行过滤后得到的新文档的位置)等信息。前几个月
笔者就因为在实验室里的一个实验性的项目做了一些需要遍历Lucene索引的工作。
事实上,如果我们需要观察Lucene索引的内容,我们完全可以使用Luke,但是我们知道Luke所提供的信息并不是总能满足我们的需要,而且很
多人都认为Luke的功能十分强大,但是实际上我们自己完全可以自己开发一个类似Luke的工具。只要你对Java界面编程比较熟悉的话(这通常是比较难
的),那么仅仅需要知道一些本文即将阐述的几个Lucene API就可以了。
这里我们遍历索引的思路是,首先得到索引词,然后根据索引词得到关于这个索引词的相关信息(主要就是根据倒排文件的结构遍历)。第一步就是得到索引
词的枚举器(enumeration),在Lucene里为我们提供了TermEnum类,该类位于org.apache.lucene.index包
下,它的声明为
public abstract class TermEnum
extends Object
根据官方的API说明,该类是一个用于枚举索引词的抽象类。索引词枚举器总是按照Term.compareTo()进行排序。索引词枚举器中的任意一个词
都比它之前的词要大。
它只有一个无参构造方法。除了继承自Object类的方法外,它主要有以下几个方法:
abstract void
close()
关闭枚举器,释放资源。
abstract int
docFreq()
返回当前索引词的文档频率。
abstract boolean
next()
枚举器向后移动一个位置。
boolean
skipTo(Term target)
使枚举器向后移动,直到移动到某个大于等于(这里的比较概念是由Term.compareTo()定义的)target的词为止。
abstract Term
term()
返回当前枚举器所枚举的词。
当我们看到TermEnum是一个抽象类的时候,我们也许会很无奈的想,我们必须要找到合适的并且已经继承了该类的非抽象类,然后还不得不对着它的
文档再研读一番。你这么想是完全正确的,但是事实上我们完全没有必要这样做,因为Lucene的IndexReader类实际上为我们提供了一个很实用的
方法
abstract TermEnum
terms()
返回一个关于当前索引中所有索引词的一个枚举器。
您也许觉得我玩你,因为该方法也是一个抽象方法,因此IndexReader本身也是一个抽象方法!难道我们还需要找到一个继承该类的非抽象类么?
当然不需要。我们有IndexSearcher类!而且令人振奋的是,该类终于不是抽象的啦!它含有一个我们神往的方法:
IndexReader
getIndexReader()
返回该搜索对应的索引的索引阅读器。
但是您很可能又提出疑问了,IndexReader不是一个抽象类么,怎么能够返回一个抽象对象呢?是的,IndexReader的确是一个抽象方
法,但是我们完全有理由相信该方法返回的实际上是一个继承自IndexReader的非抽象类。Lucene此处使用的是Java的多态,至于返回的到底
是IndexReader的哪一个子类我们大可不必细究,交给JVM就好了。因此,我们就可以使用前面的所有的那些抽象方法(注意,当我们使用这些方法的
时候,它们不再是抽象方法)了。
因此,得到一个索引的索引词就可以使用下面这段代码:
IndexSearcher searcher = new IndexSearcher(IndexPath);
IndexReader reader = searcher.getIndexReader();
TermEnum enumeration = reader.terms();
while(enumeration.next()){
//invoke the other methods in TermEnum
}
如果您是一个细心的读者,您可能会问到:enumeration.next()不是会枚举出下一个词么,那么上面那段代码不就会直接跳过第一个索引
词么?是的,如果您这么想,那说明您考虑的很细致,但是我可以告诉您,上面的代码完全没有问题。因为一开始TermEnum枚举的并不是第一个索引词而是
一个空对象,因此在我们使用TermEnum的其他方法之前应当首先调用next()方法。
现在我们能够得到所有的索引词了,那么怎么根据这些索引词得到其他信息(出现的文章、位置等)呢?事实上,原理完全和上面的方法差不多,只是使用的
方法不同而已。
如果刚才我们仔细阅读Lucene关于IndexReader的API文档的话,那么我们可以发现一个方法:
TermPositions
termPositions(Term term)
返回一个包含term的所有文档的枚举器。
现在我们就来看看TermPositions。我们可以发现,TermPositions并不是一个类,而是一个接口,而且该接口是继承自
TermDocs接口的。现在我们暂且不看TermDocs,先来了解一下TermPositions接口,该接口的API说明文档是这样阐述的:
public interface TermPositions
extends TermDocs
TermPositions 提供枚举一个词的<document, frequency, <position>*
>三元组的接口 。
其中,document 和 frequency 的含义与 TermDocs中的相同。
而position部分则顺序列出了一个词在一个文档中的每一个出现位置。
该接口含有一个方法:
int
nextPosition()
返回在当前文档中的下一个出现位置。
使用该方法我们就可以自如地遍历上面三元组的position部分了,也就是说我们可以得到一个词在一个文档中的所有出现位置了!
但是您可能觉得这点信息实在是少得可怜。别着急,前面说过TermPositions接口是继承自TermDocs接口的(真是惊讶于Lucene
的体系架构,你完全可以把Lucene的设计作为一个设计模式的范例去学习),那么TermDocs接口应该为我们设计了更多的实用方法。事实确实如此!
我们完全没有必要去全面的了解TermDocs接口,我们现在所需要知道的就是TermPositions接口究竟从TermDocs接口继承了哪
些方法。从TermPositions的API文档处就可以轻易地发现它继承了如下方法:close, doc, freq, next, read,
seek, seek,
skipTo。这些方法几乎都是自解释的,这里就不再赘述每一种方法了,感兴趣的读者可以自行参阅Lucene的API说明文档。有了这些方法,我们就可
以完成我们对Lucene索引文件的遍历了。这里我需要强调一下,虽然我们没有实现任何实现了上面接口的类,但是我们在调用
reader.termPositions(Term
term)方法时实际上Lucene给我们返回了一个实现了TermPositions接口的类的实例(如果您对这点仍然不甚了然的话,请您再去翻翻您的
Java教程)。
利用下面这段代码,我们可以对于一个给定的Lucene索引打印出<term, document, frequency,
<position>* >四元组。
IndexSearcher searcher = new
IndexSearcher(IndexPath);//根据指定的路径构造一个搜索器
IndexReader reader = searcher.getIndexReader();//得到搜索器的索引阅读器
TermEnum enumeration = reader.terms();//得到索引的索引词表
while(enumeration.next())//遍历索引此表
{
if(enumeration.term().field().equals("content"))//我们仅处理所在域域名为content的索引词
{
//out是一个输出流,它输出到一个文本,这里没有给出out的定义,读者可以自己定义它
out.write(enumeration.term().text() + "\n");
TermPositions posEnum = reader.termPositions(new
Term("content",enumeration.term().text()));
StringBuffer sb = new StringBuffer(65536);
while(posEnum.next())
{
sb.append(reader.document(posEnum.doc()).getField("DOCNO").stringValue());//DOCNO
是笔者所使用语料的文档的标号,对应一般使用者的"filename"域
sb.append(":");
sb.append(posEnum.freq());
sb.append(" ");
for( int i = 0; i < posEnum.freq(); i++)
sb.append("["+posEnum.nextPosition()+"]");
sb.append(";");
}
out.write(sb.toString()+"\n");
}
out.close();
searcher.close();
这样,我们就完成了一个简单的索引遍历的操作。打印出的结果的一个局部视图如下:
modifyits
AP890915-0286 :1 [317]; AP890918-0217 :1 [368]; AP891215-0011 :1 [245];
modifyrecipes
AP890830-0142 :1 [332];
modifyself
AP890914-0048 :2 [83] [126];
modifythe
AP890814-0212 :1 [133]; AP890923-0115 :1 [58];
以"modifyself"来说,它出现在文档编号为AP890914-0048的文档中,在该文档中出现2次,位置分别是83和126。
当然,你可以使用更多的方法来打印出更多的信息。
好了,至此我们已经把基本的遍历Lucene索引的API及其使用介绍完了,你是不是觉得Luke实际上也没有很神秘呢?你完全有能力自己写一个
Lucene索引查看器。
P.S.
本文完全是笔者自己从在使用经验中总结出来的,由于笔者自己也是刚接触Lucene,因此理解难免有偏颇之处,希望大家指正。同时笔者所使用的
Lucene版本为2.0.0版,使用的API文档也是针对本版本的英文帮助(文中关于API的官方说明系笔者根据英文版翻译而来,若有错漏之处尽请指
正)。
分享到:
相关推荐
以下是对Lucene索引机制的详细解析: 一、Lucene的索引过程 1. 文档分析:当向Lucene添加文档时,首先会经过一个分词器(Tokenizer),将文本拆分成一系列的词项(Token)。接着,这些词项会被过滤(Filter)和...
在使用 Lucene 进行信息检索时,有时我们需要对建立的索引进行查看、调试或分析,这时就需要借助 Lucene 的索引查看工具。 Luke 是一个非常实用的 Lucene 索引浏览器,全称为 Lucidworks Luke。它允许用户以图形化...
- 使用Lucene提供的API来创建索引。 - 需要创建一个`IndexWriter`对象,指定索引存储的位置及索引的配置选项。 - 对于每个XML文档中的元素,可以创建一个`Document`对象,并将其添加到`IndexWriter`中。 3. **...
- **首次创建索引**:首先,我们需要遍历整个数据源,创建每个文档的实例,然后将这些文档添加到Lucene的索引writer中。完成这一步后,就会生成一个完整的初始索引。 - **监控数据变更**:为了实现增量索引,我们...
**Lucene索引和查询** Lucene是Apache软件基金会的开放源码全文搜索引擎库,它提供了文本检索的核心工具,使得开发者能够快速构建自己的搜索应用。本项目中的代码旨在展示如何利用Lucene对多个文件夹下的数据进行...
**Lucene API** Lucene API 是一个开源的全文搜索引擎库,由Apache软件基金会开发并维护。它是Java语言实现的,但提供了多种语言的接口,包括Python、C#、PHP等,使得开发者能够在各种环境中构建高效的全文检索应用...
本篇文章将详细介绍如何使用Lucene3.0来创建索引,并通过一个具体的例子来演示整个过程。 #### 一、Lucene3.0简介 Lucene是一款高性能、全功能的全文搜索引擎库。它为开发者提供了构建搜索应用所需的所有基本工具...
二、Lucene索引创建流程 1. 初始化:首先,我们需要导入Lucene库,并创建一个标准的Analyzer,例如StandardAnalyzer,它对输入的文本进行标准化处理。 2. 创建索引目录:索引数据会存储在一个Directory对象中,...
以下是关于使用Lucene实现索引查询的详细知识: ### 一、创建索引 创建索引是Lucene的核心过程,它涉及到以下步骤: 1. **定义索引目录**:首先,你需要指定一个目录来存储索引文件。这通常是一个文件夹,可以...
在本文中,我们将探讨如何使用Lucene对这些文件类型进行全文检索的实现。 首先,为了实现全文检索,我们需要创建索引。在Lucene中,`IndexWriter` 类是负责创建和更新索引的主要工具。在`LuceneCreateIndex` 类中,...
Apache Lucene作为一款强大的全文搜索引擎库,它为开发者提供了丰富的API和算法,使得开发者能够快速构建自己的搜索功能。基于Lucene的索引与搜索技术,不仅涉及到数据的高效存储和检索,还包括了文本预处理、分词、...
从索引的构建到查询的执行,每个步骤都涉及到对 Lucene API 的深入理解。通过学习这个示例,开发者可以进一步了解 Lucene 的工作原理,并将其应用到自己的项目中,提升搜索功能的效率和用户体验。
**Lucene简介** Lucene是Apache软件基金会的一个开放源代码项目,它是一个高性能、全文本检索库,...通过上述步骤,你可以在MyEclipse10环境下使用Lucene快速建立和搜索索引,为你的应用程序添加强大的全文检索功能。
`IndexerFile.java`是索引器类,负责读取Access数据库中的数据并构建Lucene索引。它可能包含以下步骤: 1. 连接Access数据库:使用JDBC驱动连接到`tangshi.mdb`数据库文件。 2. 查询数据:从数据库中获取待索引的...
Lucene索引的构建和查询都是基于反向索引进行的,这意味着当用户输入查询词时,Lucene能够迅速找到包含这些词的所有文档,而不必遍历整个文档集。 #### 索引文件格式 Lucene索引文件格式是其内部设计的关键部分,...
- 当查询执行时,Lucene会遍历倒排索引,找到匹配的文档,并根据相关性评分(Relevance Scoring)来排序结果。 - 相关性评分通常基于TF-IDF算法,结合术语频率和文档频率计算,高分代表更相关的文档。 - 高亮显示...
- `lukeall-0.8.1.jar`:Luke是一个用于查看和分析Lucene索引的工具,可以帮助开发者调试和理解索引结构。 - `log4j-1.2.12.jar`:日志框架,用于记录程序运行时的信息。 - `commons-httpclient-3.1.jar`:可能是...