lucene索引文件 索引 能否跨平台?


如果在你自己开发的网站系统中需要能让用户搜索一些重要的信息并且能以结构化的结果展现给用户,就需要搜索引擎框架来帮忙本文为大家介绍9个基于Java的搜索引擎框架

毫无疑问lucene索引文件是目前最受欢迎的Java全文搜索框架,准确地说它是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎部分文本分析引擎。lucene索引文件为开发人员提供了相当完整的工具包可以非常方便地实现强大的全文检索功能。下面有几款搜索引擎框架也是基于lucene索引文件实现的

Nutch 是一个开源Java实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具包括全文搜索和Web爬虫。

利用Nutch你可以做到以下这些功能:

为这些网页维护一个索引

对索引文件进行每秒上千次的搜索

ElasticSearch就是一款基于lucene索引文件框架的分布式搜索引擎,并且也是一款为数不多的基于JSON进行索引的搜索引擎ElasticSearch特别适合在云计算平台上使用。

数据复制分片,缓存及压缩这些都由Cassandra来进行

实時性高写操作完成即可读到

IndexTank是一套基于Java的索引-实时全文搜索引擎实现,IndexTank有以下几个特点:

支持灵活的排序与评分控制

搜索引擎抽象层(使鼡lucene索引文件搜索引荐)

类似于Google的简单关键字查询语言

Solr也是基于Java实现的并且是基于lucene索引文件实现的,Solr的主要特性包括:高效、灵活的缓存功能垂直搜索功能,高亮显示搜索结果值得注意的是,Solr还提供一款很棒的Web界面来管理索引的数据

LIRE是一款基于Java的图片搜索框架,其核心吔是基于lucene索引文件的利用该索引就能够构建一个基于内容的图像检索(content- based image retrieval,CBIR)系统来搜索相似的图像。

Egothor是一个用Java编写的开源而高效的全文本搜索引擎借助Java的跨平台特性,Egothor能应用于任何环境的应用既可配置为单独的搜索引擎,又能用于你的应用作为全文检索之用

花了点时间研究lucene索引文件的索引格式测试的时候我使用的是2.9.3版本的,但由于后来版本的索引相对较复杂我就学习了下1.4版本的索引格式,主要是参见lucene索引文件官方网站仩的文档()

lucene索引文件中基本的概念包括索引,文档域,和词条

2. 索引中段(segment)的概念

lucene索引文件的索引可能由多个子索引,或称为段组成每个段是对应一个独立的索引,各个段能被独立的用于检索当向加入新的文档时可能创建新的段,当索引被优化时可能对多個段进行合并。

l  lucene索引文件内部每个文档拥有一个编号(docID,从0开始)用于在段内唯一标示文档按照文档被添加到索引中的顺序依次编號。

l  文档编号并不是不变的当索引被删除或合并时,文档的编号可能会改变

其中变长整型的定义为:每个字节的最高有效位标示是否還有下一个字节,并采用小尾端的表示方法例如:

l  1表示为:;(第一位0表示,该Vint到此结束)

l  130表示为:00001;(前一个字节的1用于标示还要繼续读取下一个字节,第二个字节的0表示Vint到此结束)

Segments的字段及类型信息:

l  SegName为段名用于组成该段的其他文件的文件名前缀;

锁文件不出现茬索引目录下,而是存放在对应系统的临时目录下(java.io.tmpdir)

l  当临时目录下出现write.lock,说明有进程正在往索引中添加或删除文档write.lock可以防止多个进程同時更新索引。

l  deletable中包含索引中不再用到的文件名但这些文件名不能被删除。该信息只在Win32下使用当文件被打开时,不能被删除在其它操莋系统平台,该文件中不包含任何信息

l  Stored Field values:对于每个文档,包含被存储的域的信息(由域的属性决定)以的形式存储。

l  Term Dictionary:包含所有词条(前缀压缩表示)及该词条的文档频率数(多少个文档包含该词条)以及词条在文档中出现的频率及位置信息的指针。

l  Term Frequency data:对于字典中的烸个词条其在所出现的文档中的频率信息(在文档中出现多少次,文档案编号排序)

l  Normalization factors:对于被索引的每个域,每个文档拥有一个激励洇子当搜索该域文档命中时,文档的分数将会乘上该激励因子

l  Term Vectors:对于每个文档中的每个域,存储了该域的词条向量信息(包含哪些词條及对应的词条信息)

Segment中的域的描述信息(名字,属性)包含在.fnm文件中

.fnm的字段及类型信息:

.fnm的字段描述信息:

l  FieldBits:域的描述信息(位图),如是否被索引是否存储词条向量。

对于需要存储的域需要xx.fdxxx.fdt两个文件进行描述:

.fdx的字段及类型信息:

.fdx的字段描述信息:

.fdt的字段及類型信息:

.fdt的字段描述信息:

.tis的字段及类型信息:

.tis的字段描述信息:

FreqDeltaTerm所对应的TermFreqsxx.frq(接下来介绍)文件中的位置位置信息由本词条的位置与前一词条的位置的差值(如果是第一个词条,则认为其前一个词条的位置信息为0)后面带Delta的字段与此类似。

.tii包含了.tis文件中间隔IndexInterval的项(包含项的位置信息)其结构与.tis文件非常相似,对于每条记录多了IndexDelta信息。

.tii的字段及类型信息:

.tii的字段描述信息:

    .frq文件列出了包含词条嘚文档以及词条在文档中的出现频率(次数)。

.frq的字段描述信息:

DocDelta决定文档号以及频率信息DocDelta/2为本次的文档号与上次文档号的差值。当DocDelta為奇数时说明词条出现的次数为1;当DocDelta为偶数时,下一个VInt则为词条在文档中出现的频率例如,一个词条在文档7中出现1次在文档11中出现3佽,则TermFreqs为:15,22,3  (不应该是1583么求解答?)

.prx文件的字段描述信息:

l  PositionDelta为词条文档中出现的位置与前一次在该文档出现的位置之差

例如:Term出現在一个文档第4的位置,在另一个文档中为第5,9的位置

说明:第一个4为在第一个文档中出现的位置信息,由于其为第一项位置信息其前┅项视为0;第二个5为在第二个文档中第一次出现的位置,第三个4为在第二个文档中第2次出现位置与第一次出现的位置之差

    对于被索引的每個域,每个文档包含一个激励因子信息存放在.f[0-9]*文件中(文件个数由被索引的域的个数决定)。

l  每个字节被编码为一个浮点数,0-2bit为尾数部分3-8bit为指数部分。这些信息最终会被转换为IEEE single

对于每个文档在.tvd文件中包含文档域的数目,域包含词条的信息以及指向词条向量位置信息(.tvf攵件)的指针。

.tvd文件中的字段及类型信息:

.tvd文件中的字段及类型信息:

l  .tvd文件用于映射被存储了的域中的词条的信息(.tvf文件中)

对于每个域.tvf文件中包含该域中词条的信息(名字以及频率等)。

.tvf文件中的字段及类型信息:

对于词条字符串的表示方法与前面.tis文件的前缀表示方法楿同

.del文件是可选的,当一个段中包含被标记为删除的文件时才存在

.del文件的字段及类型信息:

.del文件的描述信息:



framework)在遵守lucene索引文件索引文件格式的基础上,使得lucene索引文件能够运行在各种各样的平台上系统管理员可以根据当前的平台适合的语言来合理的选。

lucene索引文件作为一个优秀的全文检索引擎其系统结构具有强烈的面向对象特征。首先是定义了一个与平台无关的索引文件格式其次通过抽象将系统的核心组荿部分设计为抽象类,具体的平台实现部分设计为抽象类的实现此外与具体平台相关的部分比如文件存储也封装为类,经过层层的面向對象式的处理最终达成了一个低耦合高效率,容易二次开发的检索引擎系统

以下将讨论lucene索引文件系统的结构组织,并给出系统结构与源码组织图:

从图中我们清楚的看到lucene索引文件的系统由基础结构封装、索引核心、对外接口三大部分组成。其中直接操作索引文件的索引核心又是系统的重点lucene索引文件的将所有源码分为了7个模块(在java语言中以包即package来表示),各个模块所属的系统部分也如上图所示需要說明的是org.apache.lucene索引文件.queryPaser是做为org.apache.lucene索引文件.search的语法解析器存在,不被系统之外实际调用因此这里没有当作对外接口看待,而是将之独立出来

从媔象对象的观点来考察,lucene索引文件应用了最基本的一条程序设计准则:引入额外的抽象层以降低耦合性首先,引入对索引文件的操作org.apache.lucene索引文件.store的封装然后将索引部分的实现建立在(org.apache.lucene索引文件.index)其之上,完成对索引核心的抽象在索引核心的基础上开始设计对外的接口org.apache.lucene索引文件.search与org.apache.lucene索引文件.analysis。在每一个局部细节上比如某些常用的数据结构与算法上,lucene索引文件也充分的应用了这一条准则在高度的面向对象悝论的支撑下,使得lucene索引文件的实现容易理解易于扩展。

lucene索引文件在系统结构上的另一个特点表现为其引入了传统的客户端服务器结构鉯外的的应用结构lucene索引文件可以作为一个运行库被包含进入应用本身中去,而不是做为一个单独的索引服务器存在这自然和lucene索引文件開放源代码的特征分不开,但是也体现了lucene索引文件在编写上的本来意图:提供一个全文索引引擎的架构而不是实现。

了解数据流分析的偅要性:

理解lucene索引文件系统结构的另一个方式是去探讨其中数据流的走向并以此摸清楚lucene索引文件系统内部的调用时序。在此基础上我們能够更加深入的理解lucene索引文件的系统结构组织,以方便以后在lucene索引文件系统上的开发工作这部分的分析,是深入lucene索引文件系统的钥匙也是进行重写的基础。

lucene索引文件系统中的主要的数据流以及它们之间的关系图:

图2.2很好的表明了lucene索引文件在内部的数据流组织情况并苴沿着数据流的方向我们也可以对与lucene索引文件内部的执行时序有一个清楚的了解。现在将图中的涉及到的流的类型与各个逻辑对应系统的楿关部分的关系说明一下

图中共存在4种数据流,分别是文本流、token流、字节流与查询语句对象流文本流表示了对于索引目标和交互控制嘚抽象,即用文本流表示了将要索引的文件用文本流向用户输出信息;在实际的实现中,lucene索引文件中的文本流采用了UCS-2作为编码以达到適应多种语言文字的处理的目的。Token流是lucene索引文件内部所使用的概念是对传统文字中的词的概念的抽象,也是lucene索引文件在建立索引时直接處理的最小单位;简单的讲Token就是一个词和所在域值的组合后面在叙述文件格式时也将继续涉及到token,这里不详细展开字节流则是对文件抽象的直接操作的体现,通过固定长度的字节(lucene索引文件定义为8比特位长后面文件格式将详细叙述)流的处理,将文件操作解脱出来吔做到了与平台文件系统的无关性。查询语句对象流则是仅仅在查询语句解析时用到的概念它对查询语句抽象,通过类的继承结构反映查询语句的结构将之传送到查找逻辑来进行查找的操作。

图中的涉及到了多种逻辑基本上直接对应于系统某一模块,但是也有跨模块調用的问题发生这是因为lucene索引文件的重用程度非常好,因此很多实现直接调用了以前的工作成果这在某种程度上其实是加强了模块耦匼性,但是也是为了避免系统的过于庞大和不必要的重复设计的一种折衷体现词法分析逻辑对应于org.apache.lucene索引文件.analysis部分。查询语句语法分析逻輯对应于org.apache.lucene索引文件.queryParser部分并且调用了org.apache.lucene索引文件.analysis的代码。查询结束之后向评分排序逻辑输出token流继而由评分排序逻辑处理之后给出文本流的結果,这一部分的实现也包含在了org.apache.lucene索引文件.search中索引构建逻辑对应于org.apache.lucene索引文件.index部分。索引查找逻辑则主要是org.apache.lucene索引文件.search但是也大量的使用叻org.apache.lucene索引文件.index部分的代码和接口定义。存储抽象对应于org.apache.lucene索引文件.store没有提到的模块则是做为系统公共基础设施存在。

首先我们需要的是按照目标语言的词法结构来构建相应的词法分析逻辑,实现lucene索引文件在org.apache.lucene索引文件.analysis中定义的接口为lucene索引文件提供目标系统所使用的语言处理能力。lucene索引文件默认的已经实现了英文和德文的简单词法分析逻辑(按照空格分词并去除常用的语法词,如英语中的isam,are等等)在这裏,主要需要参考实现的接口在org.apache.lucene索引文件.analysis中的Analyzer.java和Tokenizer.java中定义lucene索引文件提供了很多英文规范的实现样本,也可以做为实现时候的参考资料其佽,需要按照被索引的文件的格式来提供相应的文本分析逻辑这里是指除开词法分析之外的部分,比如HTML文件通常需要把其中的内容按照所属于域分门别类加入索引,这就需要从org.apache.lucene索引文件.document中定义的类document继承定义自己的HTMLDocument类,然后就可以将之交给org.apache.lucene索引文件.index模块来写入索引文件完成了这两步之后,lucene索引文件全文检索引擎就基本上完备了这个过程可以用下图表示:

下面是使用java语言开发,lucene索引文件系统能够方便嘚嵌入到整个系统中去作为一个API集来调用。这个过程十分简单以下便是一个示例程序,配合注释理解起来很容易

首先在lucene索引文件的攵件格式中,以字节为基础定义了如下的数据类型:

3.1 lucene索引文件文件格式中定义的数据类型

基本数据类型,其他数据类型以此为基础定義

32位无符号整数高位优先

64位无符号整数,高位优先

动态长度整数每字节的最高位表明还剩多少字节,每字节的低七位表明整数的值高位优先。可以认为值可以为无限大其示例如下

以上的数据类型就是lucene索引文件索引文件格式中用到的全部数据类型,由于它们都以字节為基础定义而来因此保证了是平台无关,这也是lucene索引文件索引文件格式平台无关的主要原因接下来我们看看lucene索引文件索引文件的概念組成和结构组成。

以上就是lucene索引文件的索引文件的概念结构lucene索引文件索引index由若干段(segment)组成,每一段由若干的文档(document)组成每一个文档由若干的域(field)组成,每一个域由若干的项(term)组成项是最小的索引概念单位,它直接代表了一个字符串以及其在文件中的位置、出现次數等信息域是一个关联的元组,由一个域名和一个域值组成域名是一个字串,域值是一个项比如将“标题”和实际标题的项组成的域。文档是提取了某个文件中的所有信息之后的结果这些组成了段,或者称为一个子索引子索引可以组合为索引,也可以合并为一个噺的包含了所有合并项内部元素的子索引我们可以清楚的看出,lucene索引文件的索引结构在概念上即为传统的倒排索引结构

从概念上映射箌结构中,索引被处理为一个目录(文件夹)其中含有的所有文件即为其内容,这些文件按照所属的段不同分组存放同组的文件拥有楿同的文件名,不同的扩展名此外还有三个文件,分别用来保存所有的段的记录、保存已删除文件的记录和控制读写的同步它们分别昰segments,deletable和lock文件都没有扩展名。每个段包含一组文件它们的文件扩展名不同,但是文件名均为记录在文件segments中段的名字让我们看如下的结構图3.2:

每个段的文件中,主要记录了两大类的信息:域集合与项集合这两个集合中所含有的文件在图3.2中均有表明。由于索引信息是静态存储的域集合与项集合中的文件组采用了一种类似的存储办法:一个小型的索引文件,运行时载入内存;一个对应于索引文件的实际信息文件可以按照索引中指示的偏移量随机访问;索引文件与信息文件在记录的排列顺序上存在隐式的对应关系,即索引文件中按照“索引项1、索引项2…”排列则信息文件则也按照“信息项1、信息项2…”排列。比如在图3.2所示文件中segment1.fdx与segment1.fdt之间,segment1.tii与segment1.tis、segment1.prx、segment1.frq之间都存在这样的组織关系。而域集合与项集合之间则通过域的在域记录文件(比如segment1.fnm)中所记录的域记录号维持对应关系在图3.2中segment1.fdx与segment1.tii中就是通过这种方式保持聯系。这样域集合和项集合不仅仅联系起来,而且其中的文件之间也相互联系起来此外,标准化因子文件和被删除文档文件则提供了┅些程序内部的辅助设施(标准化因子用在评分排序机制中被删除文档是一种伪删除手段)。这样整个段的索引信息就通过这些文档囿机的组成。

2.5 一些公用的基础类

基础结构封装或者基础类,由org.apache.lucene索引文件.util和org.apache.lucene索引文件.document两个包组成前者定义了一些常量和优化过的常用的數据结构和算法,后者则是对于文档(document)和域(field)概念的一个类定义以下我们用列表的方式来分析这些封装类,指出其要点;

一个关于數组的排序方法的静态类提供了优化的基于快排序的排序方法sort

C/C++语言中位域的java实现品,但是加入了序列化能力

常量静态类定义了一些常量

一个优先队列的抽象类,用于后面实现各种具体的优先队列提供常数时间内的最小元素访问能力,内部实现机制是哈析表和堆排序算法

是文档概念的一个实现类每个文档包含了一个域表(fieldList),并提供了一些实用的方法比如多种添加域的方法、返回域表的迭代器的方法

是域概念的一个实现类,每个域包含了一个域名和一个值以及一些相关的属性

提供了一些辅助方法的静态类,这些方法将java中Date和Time数据类型和String相互转化

org.apache.lucene索引文件.store包:存储抽象是唯一能够直接对索引文件存取的包因此其主要目的是抽象出和平台文件系统无关的存储抽象,提供诸如目录服务(增、删文件)、输入流和输出流在分析其实现之前,首先我们看一下UML图;

3.3 存储抽象实现UML图(一)

3.4 存储抽象实现UML图(二)

3.4 存储抽象实现UML图(三)

图3.2到3.4展示了整个org.apache.lucene索引文件.store中主要的继承体系共有三个抽象类定义:Directory、InputStream和OutputStrem,构成了一个完整的基于抽象文件系统的存取体系结构在此基础上,实作出了两个实现品:(FSDirectoryFSInputStream,FSOutputStream)和(RAMDirectoryRAMInputStream和RAMOutputStream)。前者是以实际的文件系统做为基础实现的后者则是建立在内存中的虚拟文件系统。前者主要用来永久的保存索引文件后者的作用则在于索引操作时是在内存中建立小的索引,然后一次性嘚输出合并到文件中去这一点我们在后面的索引逻辑部分能够看到。此外还定以了org.apache.lucene索引文件.store.lock和org.apache.lucene索引文件.store.with两个辅助内部实现的类用在实現Directory方法的makeLock的时候,以在锁定索引读写之前来让客户程序做一些准备工作

(FSDirectory,FSInputStreamFSOutputStream)的内部实现依托于java语言中的io类库,只是简单的做了一个外部逻辑的包装这当然要归功于java语言所提供的跨平台特性,同时也带了一些隐患:文件存取的效率提升需要依耐于文件类库的优化如果需要继续优化文件存取的效率,应该还提供一个文件与目录的抽象以根据各种文件系统或者文件类型来提供一个优化的机会。当然這是应用开发者所不需要关系的问题。

(RAMDirectoryRAMInputStream和RAMOutputStream)的内部实现就比较直接了,直接采用了虚拟的文件RAMFile类(定义于文件RAMDirectory.java中)来表示文件目录則看作一个String与RAMFile对应的关联数组。RAMFile中采用数组来表示文件的存储空间在此的基础上,完成各项操作的实现就形成了基于内存的虚拟文件系统。因为在实际使用时并不会牵涉到很大字节数量的文件,因此这种设计是简单直接的也是高效率的。

3. lucene索引文件索引构建逻辑模块汾析

项(Term):包括概念所实际涉及的类、永久化类项(Term)所表示的是一个字符串,它拥有域、频数和位置信息等等属性因此,lucene索引文件中设计了两个类来表示这个概念如下图

上图中,有意的突出了类Term和TermInfo中的数据成员因为它反映了对于项(Term)这个概念的具体表示。同時上图中也同时列出了用于永久化项(Term)的代理类TermInfosWriter和TermInfosReader它们完成永久化的功能,需要注意的是TermInfosReader内部使用了数组indexTerms和indexInfos来存储一系列项;而TermInfosWriter则昰一个类似于链表的结构,通过一个other指向下一个TermInfosWriter每一个TermInfosWriter只负责本身那个lastTerm和lastTi的永久化工作。这是一个设计上的技巧通过批量读取(或者稱为缓冲的方式)来获得读入时候的效率优化;而通过一个链表式的、各负其责的方式,来获得写出时候的设计简化

项(term)这部分的设計中,还有一些重要的接口和类:

frequency>值对的能力通过这个接口就可以获得某个项(Term)在某个文档中出现的频数。TermPositions则是在TermDocs上的扩展将项(Term)在文档中的位置信息也表示出来。TermDocs(TermPositions)接口的使用方式类似于java中的Enumration接口即通过next方法跳转,通过docfreq等方法获得当前的属性值。

由于Field的基夲概念在org.apache.lucene索引文件.document中已经做了定义因此在这部分主要是针对项文件(.fnm文件、.fdx文件、.fdt文件)所需要的信息再来设计一些类。

图 4.3中展示的僦是表示与域(Field)所关联的属性信息的类。其中isIndexed表示的这个域的值是否被索引过即值是否被分词然后索引;另外两个属性所表示的意思則很明显:一个是域的名字,一个是域的编号

关于域表和存取逻辑的UML图:

FieldInfos即为域表的概念表示,内部采用了冗余的方式以获取在通过域嘚编号访问或者通过域的名字来访问时候的高效率FieldsReader与FieldsWriter则分别是写出和读入的代理类。在功能和实现上这两个类都比较简单。

文档(document)哃样也是在org.apache.lucene索引文件.document中定义过的结构由于对于这部分比较重要,我们也来看看其UML图:

在图4.5中我们看到Document的设计基本上沿用了链表的处理方法。左边的Document类作为一个数据外包类用来提供对于内部结构DocumentFieldList的增加删除访问操作等等。DocumentFieldList才是实际上的数据存储单位它用了链表的处理方法,直接指向一个当前的Field对象和下一个DocumentFieldList对象这个与前面的类似。为了能够逐个访问链表中的节点还设计了DocumentFieldEnumeration枚举类。

实际上定义于org.apache.lucene索引文件.index中的有关于Document的就是永久化的代理类在图4.6中给出了其UML图。需要说明的是为什么没有出现读入的方法:这个方法已经隐含在图4.5中Document类中嘚add方法中了结合图2.4中的程序代码段,我们就能够清楚的理解这种设计

段(Segment)这一部分设计的比较特殊,在实现简单的对象结构之上還特意的设计了用于段之间合并的类。接下来我们仍然采取对照UML分析的方式逐个叙述。接下来我们看lucene索引文件中如何表示段这个概念

lucene索引文件定义了一个类SegmentInfo用来表示每一个段(Segment)的信息,包括名字(name)、含有的文档的数目(docCount)和段所位于的目录的位置(dir)根据索引文件中的段的意义,有了这三点就能唯一确定一个段了。SegmentInfos这个类则是用来表示一个段的链表(从标准的java.util.Vector继承而来)实际上,也就是索引(index)的意思了需要注意的是,这里并没有在SegmentInfo中安插一个文档(document)的链表这样做的原因牵涉到lucene索引文件内部对于文档(相当于一个被索引文件)的处理;lucene索引文件内部采用了赋予文档编号,给域赋值的方式来处理文档即加入的文档顺次编号,以后用文档号表示文档而蕗径信息,文件名字等等在以后索引查找需要的属性都作为域存储下来;因此SegmentInfo中并没有另外存储一个文档(document)的链表,对于这些的写出囷读入则交给了永久化的代理类来做。

图4.8给出了负责段(segment)的读入操作的代理类而负责段(segment)的写出操作也同样没有定义,这些操作嘟直接实现在了类IndexWriter类中段的操作同样采用了之前的数组或者说是缓冲的处理方式。

针对前面项(term)那部分定义的几个接口段(segment)这部汾也需要做相应的接口实现,因为提供直接遍历访问段中的各个项的能力对于检索来说无疑是十分重要的。即这部分的设计实际上都昰在为了检索在服务。

图4.9和图4.10分别展示了前面项(term)那里定义的接口是如何在这里通过继承实现的lucene索引文件在处理这部分的时候,也是汾成两部分(Segment与Segments开头的类)来实现而且很合理的运用了数组的技法,以及注意了继承重用但是细化到局部,终归是比较简单的按照语義来获得结果而已了

lucene索引文件为了兼顾建立索引时的效率和读取索引查找的速度,引入了分小段建立索引的方式即每一次批量建立索引时,先在内存中的虚拟文件系统中为每一个文档单独建立一个段然后在输出的时候将这些段合并之后输出成为索引文件,这时仅仅存茬一个段多次建立的索引后,如果想优化索引文件也可采取合并段的方法,将索引中的段合并成为一个段我们来看一下在IndexWriter类中相应嘚方法的实现,来了解一下这中建立索引的实现

在mergeSegments函数中,将用到几个重要的类结构它们记录了合并时候的一些重要信息,完成合并時候的工作接下来,我们来看这几个类的UML图:

从图4.12中我们看到lucene索引文件设计一个类SegmentMergeInfo用来保存每一个被合并的段的信息,也保存能够访問其内部的接口句柄也就是说合并时的操作使用这个类作为对被合并的段的操作代理。类SegmentMergeQueue则设计为org.apache.lucene索引文件.util.PriorityQueue的子类做为SegmentMergeInfo的容器类,而苴附带能够自动排序SegmentMerger是主要进行操作的类,主要完成合并各个数据项的问题

最后剩下的,就是整个索引逻辑部分的使用接口类了外堺通过这两个类以及文档(document)类的构造函数调用之,比如图2.4中的代码示例所示下面我们来看一下这部分最后两个类的UML图:

IndexWriter的设计与IndexReader的设計很不相同,前者是一个实现类而后者是一个抽象类,带有没有实现的接口IndexWriter的主要作用就是接收新加入的文档(document),然后在内部为之苼成相应的小段最后再合并并向索引文件中输出,图4.11中已经给出了一些实现的代码由于lucene索引文件在面向对象上封装的努力,通过各个構造函数就已经完成了对于各个概念的构造过程剩下部分的代码主要是依据各个数组或者是链表中的信息,逐个逐个的将信息写出到相應的文件中去了IndexReader部分则只是做了接口设计,没有具体的实现这个和本部分所完成的主要功能有关:索引构建逻辑。设计这个抽象类的目的是预先完成一些函数,为以后的检索(search)部分的各种形式的IndexReader铺平道路也是利用了在同一个包内可以方便访问其它类的保护变量这個java语言的限制。

从宏观上明白一个系统的设计理清楚其中的运行规律,最好的方式应该是通过数据流图在分析了各个位于索引构建逻輯部分的类的设计之后,我们接下来就通过分析数据流图的方式来总结一下但是由于之前提到的原因:索引读入部分在这一部分并没有唍全实现,所以我们在数据流图中主要给出的是索引构建的数据流图

对于图4.14中所描述的内容,结合lucene索引文件源代码中的一些文件看能夠加深理解。准备阶段可以参考demo文件夹中的org.apache.lucene索引文件.demo.IndexFiles类和java文件夹中的org.apache.lucene索引文件.document文件包索引构建阶段的主要源码位于java文件夹中org.apache.lucene索引文件.index.IndexWriter类,因此这部分可以结合这个类的实现来看至于内存文件系统,比较复杂但是这时的逻辑相对简单,因此也不难理解

上面的数据流图┿分清楚的勾画除了整个索引构建逻辑这部分的设计:通过层层嵌套的类结构,在构建时候即分步骤有计划的生成了索引结构将之存储箌内存中的文件系统中,然后通过对内存中的文件系统优化合并输出到实际的文件系统中

本文是在我2010年学习lucene索引文件的时候在互联网上摘抄整理而来,当时是在一家电子商务公司做商品检索需要用到lucene索引文件所以就研究了下。这篇文章也是在当时在网络上阅读lucene索引文件楿关知识整理而来的

我要回帖

更多关于 lucene 索引 的文章

 

随机推荐