lucene-2.9.0 索引过程(三) 过程简述

本文深入探讨了Lucene的索引机制,包括文档添加、索引合并及frq、prx、tii、tis文件的写入过程。详细解释了如何通过delta编码来节省存储空间,并介绍了复合文件cfs的创建方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 索引过程
IndexWriter.addDocument(Document) line: 2428 
IndexWriter.addDocument(Document, Analyzer) line: 2454
DocumentsWriter.addDocument(Document, Analyzer) line: 750
DocumentsWriter.updateDocument(Document, Analyzer, Term) line: 772
DocFieldProcessorPerThread.processDocument() line: 254 
DocInverterPerField.processFields(Fieldable[], int) line: 195
TermsHashPerField.add() line: 391 

触发合并和写文档过程
IndexWriter.addDocument(Document) line: 2428
IndexWriter.addDocument(Document, Analyzer) line: 2475 
IndexWriter.flush(boolean, boolean, boolean) line: 4166 
IndexWriter.doFlush(boolean, boolean) line: 4175
IndexWriter.doFlushInternal(boolean, boolean) line: 4277
DocumentsWriter.flush(boolean) line: 581
DocFieldProcessor.flush(Collection, SegmentWriteState) line: 63 
DocInverter.flush(Map, SegmentWriteState) line: 76
TermsHash.flush(Map, SegmentWriteState) line: 145
FreqProxTermsWriter.flush(Map, SegmentWriteState) line: 129


1.frq文件写入 docID(delta值) + tf

FreqProxTermsWriter.flush(Map, SegmentWriteState) line: 129
FreqProxTermsWriter.appendPostings(FreqProxTermsWriterPerField[], FormatPostingsFieldsConsumer) line: 217
FormatPostingsDocsWriter.addDoc(int, int) line: 74

// 值大致是这么写的
final int delta = docID - lastDocID;

lastDocID = docID;
if (omitTermFreqAndPositions) //不记录频率和位置
    out.writeVInt(delta);
else if (1 == termDocFreq)
    out.writeVInt((delta<<1) | 1);
else {
    out.writeVInt(delta<<1);
    out.writeVInt(termDocFreq);
}

2.prx文件写入 position(delta值)
FreqProxTermsWriter.flush(Map, SegmentWriteState) line: 129
FreqProxTermsWriter.appendPostings(FreqProxTermsWriterPerField[], FormatPostingsFieldsConsumer) line: 245 
FormatPostingsPositionsWriter.addPosition(int, byte[], int, int) line: 56

 

3.tii文件写入
// 初始化
  TermInfosWriter(Directory directory, String segment, FieldInfos fis,
                  int interval)
       throws IOException {
    initialize(directory, segment, fis, interval, false); // 生成tis
    other = new TermInfosWriter(directory, segment, fis, interval, true);
    other.other = this;
  }


FreqProxTermsWriter.flush(Map, SegmentWriteState) line: 149
FormatPostingsFieldsWriter.finish() line: 71
TermInfosWriter.close() line: 220 

// 值大致是这么写的
if (!isIndex && size % indexInterval == 0)
   // other.add(lastFieldNumber, lastTermBytes, lastTermBytesLength, lastTi);                      // add an index term
{
   output.writeVInt(start);                      // write shared prefix length
   output.writeVInt(length);                     // write delta length
   output.writeBytes(termBytes, start, length);  // write delta bytes
   output.writeVInt(fieldNumber);                // write field num
   output.writeVInt(ti.docFreq);                       // write doc freq
   output.writeVLong(ti.freqPointer - lastTi.freqPointer); // write pointers
   output.writeVLong(ti.proxPointer - lastTi.proxPointer);

   if (ti.docFreq >= skipInterval)
  {
    output.writeVInt(ti.skipOffset);
  }

   if (isIndex)
  {
     output.writeVLong(other.output.getFilePointer() - lastIndexPointer);
     lastIndexPointer = other.output.getFilePointer(); // write pointer
  }  
 
}
 
4.tis文件写入
// 初始化
  TermInfosWriter(Directory directory, String segment, FieldInfos fis,
                  int interval)
       throws IOException {
    initialize(directory, segment, fis, interval, false);
    other = new TermInfosWriter(directory, segment, fis, interval, true); // 生成tii
    other.other = this;
  }

FreqProxTermsWriter.appendPostings(FreqProxTermsWriterPerField[], FormatPostingsFieldsConsumer) line: 276  
FormatPostingsDocsWriter.finish() line: 113
TermInfosWriter.add(int, byte[], int, TermInfo) line: 169
TermInfosWriter.add(int, byte[], int, TermInfo) line: 171 
TermInfosWriter.writeTerm(int, byte[], int) line: 196 

值大致是这么写的
output.writeVInt(start);                      // write shared prefix length
output.writeVInt(length);                     // write delta length
output.writeBytes(termBytes, start, length);  // write delta bytes
output.writeVInt(fieldNumber);                // write field num
output.writeVInt(ti.docFreq);                       // write doc freq
output.writeVLong(ti.freqPointer - lastTi.freqPointer); // write pointers
output.writeVLong(ti.proxPointer - lastTi.proxPointer);

if (ti.docFreq >= skipInterval)
{
   output.writeVInt(ti.skipOffset);
}

if (isIndex)
{
   output.writeVLong(other.output.getFilePointer() - lastIndexPointer);
   lastIndexPointer = other.output.getFilePointer(); // write pointer
}  


5.写入复合文件cfs

IndexWriter.addDocument(Document) line: 2428
IndexWriter.addDocument(Document, Analyzer) line: 2475
IndexWriter.flush(boolean, boolean, boolean) line: 4166
IndexWriter.doFlush(boolean, boolean) line: 4175
IndexWriter.doFlushInternal(boolean, boolean) line: 4321
DocumentsWriter.createCompoundFile(String) line: 614
CompoundFileWriter.close() line: 137 
 
 
合并以下文件
_0.frq
_0.nrm
_0.tii
_0.tis
_0.fnm
_0.prx
为_0.cfs


值大致是这么写的
os.writeVInt(entries.size());
{  // 遍历欲合并文件,写入文件名
   os.writeLong(0);    // for now
   os.writeString(fe.file); // file name
}
{ // 遍历欲合并文件,拷贝数据
  copyFile(fe, os, buffer);
}
{ // 遍历欲合并文件,写入文件指针
  os.seek(fe.directoryOffset);
  os.writeLong(fe.dataOffset);
}

开源全文搜索工具包Lucene2.9.1的使用。 1. 搭建Lucene的开发环境:在classpath中添加lucene-core-2.9.1.jar包 2. 全文搜索的两个工作: 建立索引文件,搜索索引. 3. Lucene索引文件逻辑结构 1) 索引(Index)由若干块(片段)(Segment)组成 ★2) 块由若干文档(Document)组成: 一个文件映射成一个文档。数据库表中的一条记录映射成一个文档。 ★3) 文档由若干域(Field)组成:文件的属性(文件路径,文件的内容)映射成一个域。记录的某个字段映射成一个域。 ☆4) 域由若干词(关键字)(Term)组成:文件的属性的内容中某个字符串映射成一个词。 4. Lucene包结构 1) analysis模块:负责词法分析及语言处理而形成Term()。提供了一些内置的分析器:最常用的是StandardAnalyzer 2) index模块:负责索引的读写。 对索引文件的segment进行写、合并、优化的IndexWriter类。对索引进行读取和删除操作的IndexReader类。 3) store模块:负责索引的存储。提供索引的各种存储类:FSDirectory,RAMDirectory等。 4) document模块:索引文件内部的基础存储结构封装。如:Document类和Field类等。 5) search模块:负责对索引的搜索。提供了索引搜索器IndexSearcher类和各种Query类,如TermQuery、BooleanQuery等。 6) queryParser模块:负责查询语句的语法分析。提供了解析查询语句的QueryParser类 7) util模块:包含一些公共工具类。 5. 创建索引 1) IndexWriter:索引写出器 a) 构造方法: IndexWriter(Directory d, Analyzer a, IndexWriter.MaxFieldLength mfl) 如果索引不存在,就会被创建。如果索引存在,就追加. IndexWriter(Directory d, Analyzer a, boolean create, IndexWriter.MaxFieldLength mfl) create为true时,原索引文件不存在就创建,存在就覆盖。 create为false时,原索引文件不存在就报错,存在就追加。 b) 常用方法: void addDocument(Document doc); //把指定文档添加到索引写出器中 void iw.close(); //关闭索引写出器,此时才把索引写到目标存储地 2) Directory: 索引存放地。 a) 文件系统:FSDirectory: FSDirectory.open(File file); b) 内存RAMDirectory: new RAMDirectory(); 3) Analyzer: 分词器。 a) StandardAnalyzer: 标准分词器。对英文采用空白, 标点符号进行分词。对中文采用单字分词。 b) SmartChineseAnalyzer: 智能中文分词器。(LUCENE_HOME/contrib/analyzers/smartcn/lucene-smartcn-2.9.1.jar) C)方的中文分词器:如PaodingAnalyzer、IKAnalyzer 4) IndexWriter.MaxFieldLength: 指定域值的最大长度。 a) UNLIMITED 无限制的。 b) LIMITED 有限制的。值为10000 5) Document: 索引的组成单元. 一组Field的集合. a) 构造方法: Document(); b) 常用方法: void add(Field f); //添加指定域到这个文档中 6) Field: 域,代表文档的某个索引. a) 构造方法: Field(String name, String value, Field.Store.YES, Field.Index.ANALYZED) name: 域的名称, 只能是字符串. value: 域的值, 只能是字符串. Field.Store: 指定Field的值是否存储或怎样存储. NO(不存储), YES(存储),COMPRESS(压缩后存储) Field.Index: 指定Field是否被索引或怎么被索引. NO(索引), ANALYZED(分词后索引), NOT_ANALYZED(不分词直接索引)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值