`
ezerg
  • 浏览: 273477 次
  • 性别: Icon_minigender_1
  • 来自: 石家庄
社区版块
存档分类
最新评论

深入学习 Lucene 3.0 索引段

阅读更多

Lucene索引index由若干段(segment)组成,每一段由若干的文档(document)组成,每一个文档由若干的域(field)组成,每一个域由若干的项(term)组成。
生成索引的代码:
		// 创建两个 Document 对象
		File f1 = new File("d:/lucene/demo1.txt");
		File f2 = new File("d:/lucene/demo2.txt");
		Document doc1 = new Document();
		doc1.add(new Field("path", f1.getPath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
		doc1.add(new Field("content", new FileReader(f1)));
		Document doc2 = new Document();
		doc2.add(new Field("path", f2.getPath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
		doc2.add(new Field("content", new FileReader(f2)));
		// 创建索引对象
		IndexWriter writer = new IndexWriter(FSDirectory.open(indexPath),
				new StandardAnalyzer(Version.LUCENE_30), true,
				IndexWriter.MaxFieldLength.LIMITED);
		// 是否复合索引
		writer.setUseCompoundFile(false);
		writer.addDocument(doc1);
		writer.addDocument(doc2);
		writer.optimize();
		writer.close();

测试生成的索引文件:_0.fdt 、_0.fdx、_0.fnm、_0.frq、_0.nrm、_0.prx、_0.tii、_0.tis、segments.gen、segments_2
测试生成的复合索引文件:_0.cfs、_0.cfx、segments.gen、segments_2
其实无论是否复合索引,两个 segments 开头的文件内容是一样的。它存储了段的详细信息,也是下面讨论的主要内容。

1、segments.gen 文件
该文件格式很简单:
version 版本号,占用4个字节。当前版本为 -2
gen0 段号0,占用8个字节
gen1 段号1,占用8个字节

版本号的代码:
参考 org.apache.lucene.index.SegmentInfos 类第 61 行
public static final int FORMAT_LOCKLESS = -2; // 该变量为 final 类型,不能被修改

写入该文件的代码:
参考 org.apache.lucene.index.SegmentInfos 类第 594 - 604 行
       int version = genInput.readInt();
       if (version == FORMAT_LOCKLESS) {
         long gen0 = genInput.readLong();
         long gen1 = genInput.readLong();
         message("fallback check: " + gen0 + "; " + gen1);
         if (gen0 == gen1) {
           // The file is consistent.
           genB = gen0;
           break;
         }
       }

读取该文件的代码:
参考 org.apache.lucene.index.SegmentInfos 类第 849 - 856 行
      IndexOutput genOutput = dir.createOutput(IndexFileNames.SEGMENTS_GEN);
      try {
        genOutput.writeInt(FORMAT_LOCKLESS);
        genOutput.writeLong(generation);
        genOutput.writeLong(generation);
      } finally {
        genOutput.close();
      }

测试生成的 segments.gen 文件十六进制表示分为三部分:
1、FFFFFFFE 显示版本号,占用 4 个字节
2、0000000000000002 显示 gen0 号,占用 8 个字节,转换十进制为 -2
2、0000000000000002 显示 gen1 号,占用 8 个字节
所以文件大小共 20 个字节

2、segments_N 文件
该文件格式比较复杂,:
FORMAT 索引文件格式的版本号。整型占用 4 个字节。
version 索引的版本号,记录了IndexWriter将修改提交到索引文件中的次数。第一次值为当前时间。长整型占用 8 个字节。
counter 是下一个新段(Segment)的段名。整型占用 4 个字节。
infos 段(Segment)的个数。整型占用 4 个字节。
info 段对象的信息:
    name 段的名称。第 1 个字节是后面占用的字节数。占用空间取决于名称的长度。
    docCount 段中包含的文档数。整型占用 4 个字节。
    delGen .del文件的版本号。长整型占用 8 个字节。
    docStoreOffset 段中如果共享其它段的域和词向量,该值为偏移地址,否则为 -1 。整型占用 4 个字节。
    docStoreSegment 段中共享其它段的域和词向量的段名称。占用空间取决于名称的长度。
    docStoreIsCompoundFile 数据是否存储在 *.cfx 文件中。占用 1 个字节。
    hasSingleNormFile  是否存在单独的标准化因子文件。占用 1 个字节。
    normGen 如果每个域有单独的标准化因子文件,则此数组描述了每个文件的版本号。占用空间取决于文件的数量,每个文件占用 8 个字节。
    IsCompoundFile 是否保存为复合文件。占用 1 个字节。
    delCount 记录了此段中删除的文档的数目。整型占用 4 个字节。
    hasProx 如果至少有一个段omitTf为false,也即词频(term freqency)需要被保存,则HasProx为1,否则为0。占用 1 个字节。
    diagnostics 调试信息。占用空间取决于调试的数量,一般值为 0,占用 4 个字节。
userData 用户信息。占用空间取决于调试的数量,一般值为 0,占用 4 个字节。
checksum 校验信息。长整型占用 8 个字节。

写入段信息的代码:
1、参考 org.apache.lucene.index.SegmentInfos 类第 338 - 347 行
      segnOutput.writeInt(CURRENT_FORMAT); // write FORMAT
      segnOutput.writeLong(++version); // every write changes
                                   // the index
      segnOutput.writeInt(counter); // write counter
      segnOutput.writeInt(size()); // write infos
      for (int i = 0; i < size(); i++) {
        info(i).write(segnOutput); // 此处参考 2
      }
      segnOutput.writeStringStringMap(userData);// 此处参考 4
      segnOutput.prepareCommit();// 此处写入长整型的校验码

2、参考 org.apache.lucene.index.SegmentInfo 类第 540 - 564 行
  void write(IndexOutput output)
    throws IOException {
    output.writeString(name);// 此处参考 3
    output.writeInt(docCount);
    output.writeLong(delGen);
    output.writeInt(docStoreOffset);
    if (docStoreOffset != -1) {
      output.writeString(docStoreSegment);
      output.writeByte((byte) (docStoreIsCompoundFile ? 1:0));
    }

    output.writeByte((byte) (hasSingleNormFile ? 1:0));
    if (normGen == null) {
      output.writeInt(NO);
    } else {
      output.writeInt(normGen.length);
      for(int j = 0; j < normGen.length; j++) {
        output.writeLong(normGen[j]);
      }
    }
    output.writeByte(isCompoundFile);
    output.writeInt(delCount);
    output.writeByte((byte) (hasProx ? 1:0));
    output.writeStringStringMap(diagnostics); // 此处参考 4 和 5 
  }

3、参考 org.apache.lucene.store.IndexOutput 类第 103 - 107 行
  public void writeString(String s) throws IOException {
    UnicodeUtil.UTF16toUTF8(s, 0, s.length(), utf8Result);
    writeVInt(utf8Result.length);// 写入名称的长度
    writeBytes(utf8Result.result, 0, utf8Result.length);// 写入名称的字节数组,长度为 utf8Result.length
  }
  public void writeVInt(int i) throws IOException {
    while ((i & ~0x7F) != 0) {// 8 位以上是否存在数据
      writeByte((byte)((i & 0x7f) | 0x80));// 第 8 位设置为 1 ,表示高位还有数据
      i >>>= 7;// 算术右移 7 位
    }
    writeByte((byte)i);
  }

4、参考 org.apache.lucene.store.IndexOutput 类第 214 - 223 行
    if (map == null) {
      writeInt(0);
    } else {
      writeInt(map.size());
      for(final Map.Entry<String, String> entry: map.entrySet()) {
        writeString(entry.getKey()); // 此处参考 3
        writeString(entry.getValue());
      }
    }
  }

5、参考 org.apache.lucene.index.IndexWriter 类第 4159 - 4170 行
    Map<String,String> diagnostics = new HashMap<String,String>();
    diagnostics.put("source", source);
    diagnostics.put("lucene.version", Constants.LUCENE_VERSION); // 大家可以看一下 Constants 类,其实它取得 Java 的环境变量
    diagnostics.put("os", Constants.OS_NAME+"");
    diagnostics.put("os.arch", Constants.OS_ARCH+"");
    diagnostics.put("os.version", Constants.OS_VERSION+"");
    diagnostics.put("java.version", Constants.JAVA_VERSION+"");
    diagnostics.put("java.vendor", Constants.JAVA_VENDOR+"");
    if (details != null) {
      diagnostics.putAll(details);
    }
    info.setDiagnostics(diagnostics);

测试生成的 segments_2 文件的十六进制表示为:
首先是所有段的公共信息
1、FFFFFFF7 索引文件格式的版本号,转换十进制为 -9
2、00000130A66E4ECA 索引的版本号,通过如下转换为知为当前的时间
//省略前面的 0 并声明为长整型
long i = 0x130A66E4ECAL;
//转化为日期类型,输出为 2011-6-19 13:45:04
System.out.println(new Date(i).toLocaleString());
3、00000001 下一个新段的段名,现在只有一个段名称为 0
4、00000001 索引中段的个数

下面每个段的详细信息
5、025F30 段的名称,02 为占用字节的个数,5F30 是UTF8编码为 _0
6、00000002 段中包含的文档数,测试使用 2 个文档
7、FFFFFFFF .del文件的版本号,如果没有删除文档则默认为 -1
8、00000000  段中如果共享其它段的域和词向量的偏移地址。
9、025F30 段的名称,02 为占用字节的个数,5F30 是UTF8编码为 _0
10、00 上面的段是否复合索引文件
11、01 是否单独的标准化因子文件
12、FFFFFFFF 因子文件的个数。测试中未生成标准化因子文件,则为 -1
13、FF 当前索引是否为复合索引文件,否为 -1
14、00000000 删除文档的数量。测试未删除为 0
15、01 词频需要被保存

下面是调用信息和用户信息
16、00000007 调试信息的数量,存在 Map 中。此处为 7 ,后面即为 7 个 key 和 value 的值
可能通过 UltraEdit 查看该项最后一个字节为 2E ,它 Sun Microsystems Inc. 的最后一个点
17、00000000 用户信息的数量,与调试信息结构相同

最后是验证码
18、00000000B171E8F7 整个索引的验证码

0
3
分享到:
评论

相关推荐

    lucene3.0庖丁+索引搜索程序

    《深入剖析Lucene3.0:庖丁解牛与索引搜索实践》 在IT行业中,搜索引擎技术扮演着至关重要的角色,而Lucene...通过深入学习其内部工作原理,结合具体的代码实践,开发者可以更好地利用Lucene3.0解决各种信息检索问题。

    Lucene 3.0 原理与代码分析完整版

    通过对《Lucene 3.0 原理与代码分析完整版》的学习,开发者不仅可以理解Lucene的工作原理,还能掌握如何定制化Lucene以满足特定需求,从而在实际项目中充分利用其强大功能。这本书是深入研究和应用Lucene不可或缺的...

    lucene3.0使用介绍及实例

    以下是一个简单的Lucene 3.0索引和搜索的Java示例: ```java import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document....

    lucene3.0资料包

    **正文** Lucene是一个开源全文检索库,由Apache软件基金会开发。它提供了强大的文本分析、索引和搜索功能,广泛应用于各种信息检索系统...通过深入学习和应用Lucene3.0,开发者可以构建出高效、智能的信息检索系统。

    lucene3.0 search

    《深入解析Lucene 3.0搜索技术》 在信息技术高速发展的今天,搜索引擎已经成为人们获取信息、解决问题的重要工具。作为开源全文检索库的代表,Apache Lucene为开发者提供了强大的文本检索功能,使得构建高效、精准...

    lucene 2.0 api以及lucene 3.0 api

    本文将深入探讨 Lucene 2.0 和 3.0 版本的主要特性和变化。 **Lucene 2.0 API 知识点** 1. **索引构建**: Lucene 2.0 提供了 `IndexWriter` 类,用于创建和更新索引。开发者可以使用 `Document` 类来封装待索引的...

    Lucene3.0增删改查和关键字高亮实例

    在这个“Lucene3.0增删改查和关键字高亮实例”项目中,我们将深入理解如何利用Lucene 3.0版本进行索引构建、文档的增删改查操作,并学习关键字高亮显示的实现方法。 首先,我们要了解**创建索引**的基本流程。在...

    Lucene 3.0完成入门

    通过以上内容的学习,你可以掌握 Lucene 3.0 的基本操作,包括如何创建索引、执行查询、优化搜索性能等。同时,了解 Compass 如何简化 Lucene 的使用,以及如何结合实际业务需求来设计和实现一个搜索引擎。在实践中...

    lucene3.0 api jar

    《深入理解Lucene 3.0 API:从jar包到实战应用》 Lucene是一个开源全文搜索引擎库,自诞生以来,它已经成为了Java世界中处理文本检索的核心工具。本篇文章将详细探讨Lucene 3.0版本的API,以及如何使用这个jar包...

    lucene3.0英文API

    1. **改进的性能**:Lucene 3.0引入了更高效的内存管理,优化了索引和搜索速度。 2. **多线程支持**:增加了对并发写入和读取的支持,提升了多用户环境下的性能。 3. **新的分析器**:提供了更多针对特定语言的...

    Lucene 3.0 原理

    **Lucene 3.0 原理解析** Lucene 是一个开源的全文搜索引擎库,由 Apache 软件基金会...对于想要深入理解 Lucene 内部工作原理的开发者,深入学习《Lucene 3.0 原理与代码分析完整版.pdf》这份文档将是极有价值的。

    lucene 3.0 中的demo项目部署

    总之,Lucene 3.0的Demo项目部署是一个动手学习Lucene功能和机制的良好途径。通过部署和运行这些示例,开发者可以迅速掌握Lucene的核心概念,并将其应用于实际项目中,提升信息检索系统的效能。

    lucene3.0学习笔记(三)与paoding整合

    在深入了解Lucene 3.0的过程中,我们经常会遇到如何将其与第三方工具进行整合的问题,以提升搜索性能和用户体验。这篇学习笔记主要关注的是将Lucene 3.0与Paoding搜索引擎进行集成的实践与技术要点。 首先,Lucene...

    lucene 3.0 API 中文帮助文档

    本篇将深入探讨Lucene 3.0 API的中文帮助文档,帮助开发者更好地理解和使用这个强大的搜索引擎。 首先,Lucene 3.0 API是Lucene的一个重要版本,它包含了丰富的类和接口,用于索引、查询和管理文本数据。这个版本的...

    lucene3.0基础实例

    本篇文章将深入探讨Lucene 3.0的基础实例,帮助读者理解和掌握如何使用这个强大的工具。 一、Lucene简介 Lucene是一个高性能、全文本搜索库,它提供了基本的索引和搜索功能,同时也支持高级查询语法。在Lucene 3.0...

    lucene 3.0 java示例

    Lucene 是一个高性能、全文本搜索库,由Apache软件基金会开发。它提供了强大的搜索功能,广泛应用于各种Java项目中。...通过研究提供的代码,你可以深入学习Lucene的工作原理,以及如何将它应用到实际项目中。

    关于全文检索的文章(使用技术Lucene3.0)

    Lucene 3.0支持多种文件格式,如倒排索引,提供高效的搜索功能,并且易于集成到各种应用程序中。 **倒排索引** 倒排索引是全文检索的核心概念。在倒排索引中,每个单词(关键词)对应一个索引列表,列表包含所有...

Global site tag (gtag.js) - Google Analytics