`

TermEnum

 
阅读更多

使用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的官方说明系笔者根据英文版翻译而来,若有错漏之处尽请指正)。

分享到:
评论

相关推荐

    城市GDP.npz

    城市GDP.npz

    基于深度学习的语音增强、去混响

    基于深度特征映射的语音增强方法 本项目为可以利用DNN和CNN的方法来进行语音增强,其中DNN使用的三个隐层每个隐层512个节点,CNN使用的是R-CED的网络结构并且加入了一些resnet来防止过拟合。你也可以选择是否使用dropout或者l2等。 使用: 第一步. 运行 ex_trac.sh 数据准备并将数据分成训练集和交叉验证集,然后提取 log spectragram 特征. 第二步. 运行 train.sh 来训练和测试模型. 第三步. 运行 ca_pesq.sh 使用PESQ来评价你的结果。

    昭春落日iPad水彩胶带第2期-课程网盘链接提取码下载 .txt

    本期课程将继续探索iPad水彩胶带绘画技巧,以昭春落日为主题,引导学员掌握绘画技巧和色彩运用,创作独特的水彩作品。通过实践与指导,学员将提升绘画技能,感受艺术的魅力,展现个性化创作,享受绘画带来的乐趣与成就感。 课程大小:8.6G

    永磁起重器使用与维护手册

    永磁起重器使用与维护手册

    机械设计测漏机sw21可编辑非常好的设计图纸100%好用.zip

    机械设计测漏机sw21可编辑非常好的设计图纸100%好用.zip

    纵横科技产品服务手册 FPM120TC-T 说明书

    纵横科技产品服务手册 FPM120TC-T 说明书

    如何提升产品的广告变现效率?.docx

    如何提升产品的广告变现效率?.docx

    机械设计灯板自动插线设备sw18可编辑非常好的设计图纸100%好用.zip

    机械设计灯板自动插线设备sw18可编辑非常好的设计图纸100%好用.zip

    LORA 模型 pantPullDownLora_pantpulldownV1.safetensors

    pantPullDownLora_pantpulldownV1

    经典CNN网络之AlexNet 对7种小麦叶片病害分类

    【基于Alexnet对7种小麦叶片病害分类】 【包含代码、数据集和训练好的权重文件,可直接运行】 项目总大小:640 MB 本数据集分为以下7类别:水泡,褐色斑点等等 下载解压后的图像目录:训练集(16,149张图片)、和测试集(678张图片) data-train 训练集-每个子文件夹放同类别的图像,文件夹名为分类类别 data-test 测试集-每个子文件夹放同类别的图像,文件夹名为分类类别 【项目介绍】 网络训练的时候采用cos 学习率自动衰减,简单测试了10个epoch。模型在测试集最好的表现达到88.9%精度,加大epoch可以增加精度。在run_results 目录下存有最好的权重文件,以及训练日志和loss、精度曲线等等 预测的时候,只需要运行predict即可,代码会自动将inference下所有图片推理,并取前三个概率最大类别的绘制在左上角 【训练自己的数据参考readme文件,不需要更改,代码会自动生成,例如分类类别个数等等】

    LORA 模型 lactation_v10.safetensors

    lactation_v10

    httpsyy70958.com29875videoplayvid45958.m3u8..m3u

    httpsyy70958.com29875videoplayvid45958.m3u8..m3u

    机械设计VFFS Makinesi-1包装机sw14非常好的设计图纸100%好用.zip

    机械设计VFFS Makinesi-1包装机sw14非常好的设计图纸100%好用.zip

    Java毕业设计-基于Springboot的医院管理系统的设计与实现 (源码+数据库+文档).zip

    基于Spring Boot的医院管理系统涉及多个功能模块,如病人管理、医生管理、预约挂号、医疗记录管理。以下是一个基本的设计和实现建议: 1. 数据库设计:设计合适的数据库模式来存储医院相关的信息,如病人信息、医生信息、预约信息等。可以使用关系型数据库(如MySQL、PostgreSQL)或非关系型数据库(如MongoDB。 2. 后端(Spring Boot)部分: - 定义实体类:根据数据库设计,在后端定义实体类来映射数据库中的表结构。 - 数据访问层(DAO):使用Spring Data JPA或者MyBatis等技术,编写数据访问层代码,用与数据库进行交互,包括增删改查等操作。 - 业务逻辑层(Service):定义业务逻辑,包括对病人、医生、预约等信息的管理和操作。可以使用@Service注解标识这些服务类,并在其中注入相应的DAO层组件。 - 控制器层(Controller):使用@RestController注解标记控制器类,定义各个接口以供前端调用。在接口中处理请求、调用服务层处理业务逻辑,并返回相应的数据。 3. 前端部分: - 页

    node-v12.22.3-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    php-8.2.18-Win32-vs16-x64.rar

    php-8.2.18-Win32-vs16-x64.rar

    node-v10.16.0-sunos-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    XC03-W4DI 说明书

    XC03-W4DI 说明书

    node-v12.22.6-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    信息技术填空选择100题

    总结出了信息技术课程常考的100道填空题,答案在花括号内。制卷时只需要将花括号及其中的内容替换成圆括号即可。

Global site tag (gtag.js) - Google Analytics