中文(中国)更改
 
powered by
Hawk Search
Hawk Search

 
分类

 
文章

 
日历

三月 2010
« 四    
1234567
891011121314
15161718192021
22232425262728
293031  
 
 
Javen-Studio Thinking of Life, Imagination of Future.
NEWS

Annotated Lucene:第四节 索引创建过程

4.3 索引创建过程

文档的索引过程是通过DocumentsWriter的内部数据处理链完成的,DocumentsWriter可以实现同时添加多个文档并将它们写入一个临时的segment中,完成后再由IndexWriter和SegmentMerger合并到统一的segment中去。DocumentsWriter支持多线程处理,即多个线程同时添加文档,它会为每个请求分配一个DocumentsWriterThreadState对象来监控此处理过程。处理时通过DocumentsWriter初始化时建立的DocFieldProcessor管理的索引处理链来完成的,依次处理为DocFieldConsumers、DocInverter、TermsHash、FreqProxTermsWriter、TermVectorsTermsWriter、NormsWriter以及StoredFieldsWriter等。

索引创建处理过程及类的主线请求链表如下图所示:

下面介绍主要步骤的处理过程

4.3.1 DocFieldProcessorPerThread.processDocument()

该方法是处理一个文档的调度函数,负责整理文档的各个fields数据,并创建相应的DocFieldProcessorPerField对象来依次处理每一个field。该方法首先调用索引链表的startDocument()来初始化各项数据,然后依次遍历每一个fields,将它们建立一个以field名字计算的hash值为key的hash表,值为DocFieldProcessorPerField类型。如果hash表中已存在该field,则更新该FieldInfo(调用FieldInfo.update()方法),如果不存在则创建一个新的DocFieldProcessorPerField来加入hash表中。注意,该hash表会存储包括当前添加文档的所有文档的fields信息,并根据FieldInfo.update()来合并相同field名字的域设置信息。

建立hash表的同时,生成针对该文档的fields[]数组(只包含该文档的fields,但会共用相同的fields数组,通过lastGen来控制当前文档),如果field名字相同,则将Field添加到DocFieldProcessorPerField中的fields数组中。建立完fields后再将此fields数组按field名字排序,使得写入的vectors等数据也按此顺序排序。之后开始正式的文档处理,通过遍历fields数组依次调用DocFieldProcessorPerField的processFields()方法进行(下小节继续讲解),完成后调用finishDocument()完成后序工作,如写入FieldInfos等。

下面举例说明此过程,假设要添加如下一个文档:

文档域

内容

是否索引

是否存储

是否分析

title

Lucene 源码分析

true

true

true

url

http://javenstudio.org

false

true

false

content

索引是如何创建的

true

true

true

content

索引的创建过程

true

true

true

下图描述处理后fields数组的数据结构

4.3.2 DocInverterPerField.processFields()

该方法负责进行文档field数据的倒排表(inverter)建立的处理工作。处理文档的有同一个名字的所有field数据,即上图的Fieldable数组,它负责将各个数据分解成(Tokenizer)一个个term并存储它们在文档中的位置及出现的频率,即Term向量和Term频率等数据。此方法负责文档的文本的分解工作(调用Analyzer),将term传递到别的consumers进行具体的数据处理,即InvertedDocConsumerPerField和InvertedDocEndConsumerPerField,在这里是TermsHash和NormsWriter。

该方法通过一个DocInverter.FieldInvertState对象来存储和统计文档的当前field的所有term出现的位置position和offset以及频率frequency等信息,同时计算该field的boost分值,为所有相同名字的fields的boost与文档的boost的乘积。通过循环调用各个consumer的start()方法检查该field是否需要进行invert处理,比如某些field是不需要索引的,或者term向量不用存储等。如果一个field需要索引但不需要分词(tokenize),则将该field整个文本数据当做一个term存储,term长度也是该文本的长度,即offset按此长度累加,position则累计加1。如果需要索引并且分词,则调用analyzer指定的tokenizer进行分词处理,分解出一个个token来创建term添加到TermsHash和NormsWriter。注意,该term的position会添加token的positionIncrement设置值(即用户指定的某些token的位置)。Offset也按token的offset值计算,这些数值由分词模块计算,可以通过分词模块调优这些数值,比如索引带有歧义的词,或者增加索引同义词等。

分词以及term添加完成后,即调用TermsHash和NormsWriter的finish()方法,统计和存储这些数据,下节详细讲解。下图描述方法处理中field的各项数据的结构:

发表评论