`
twh1224
  • 浏览: 96026 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Lucene学习(17)

阅读更多
根据16中对IndexFileDeleter类和CommitPoint类的源代码的阅读学习,在此进行总结:

一个提交点所具有的信息如下所示:

    long gen;    // 下次提交索引段segments_N的版本 
    List files;    // 属于当前索引目录的索引段的一个列表 
    String segmentsFileName;    // 一个索引段 
    boolean deleted;    // 删除标志 


一个提交点具有的行为:

1、通过getSegmentsFileName()方法,得到一个索引段文件的名称;

2、通过delete()方法,获取到具有deleted标志(当delete为false时,即还没有被删除)的提交点,加入到 commitsToDelete列表中,真正删除是在CommitPoint类的外部类IndexFileDeleter类中的 deleteCommits()方法中;

3、该类的compareTo()实现了自然排序的功能,排序是根据gen = segmentInfos.getGeneration();返回的整数值进行实现的。也就是说,如果把一个个的CommitPoint加入到列表中的时候,它是有序的,可以很方便地获取最早的提交点和最近提交点。

在IndexFileDeleter类和CommitPoint类中,都涉及到了关于索引段Segment的内容,研究一下SegmentInfos类和SegmentInfo类。
SegmentInfos类实现的源代码:

package org.apache.lucene.index; 
 
import org.apache.lucene.store.Directory; 
import org.apache.lucene.store.IndexInput; 
import org.apache.lucene.store.IndexOutput; 
 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.PrintStream; 
import java.util.Vector; 
 
final class SegmentInfos extends Vector { 
 
 
// 
public static final int FORMAT_LOCKLESS = -2; 
 
// 
public static final int FORMAT_SINGLE_NORM_FILE = -3; 
 
// 用于指向最近的文件的格式(因为Lucene2.1以后对索引文件的格式进行了优化的改变),可以参考官方文档http://lucene.apache.org/java/2_2_0/fileformats.html#Segments%20File 
private static final int CURRENT_FORMAT = FORMAT_SINGLE_NORM_FILE; 
 
public int counter = 0;    // 用于命名当前最新的索引段文件 
/** 
   * 统计索引文件变化的频率(如添加索引、删除索引会使索引文件的格式发生变化) 
   * 根据当前的时间(精确到毫秒)创建一个唯一的版本号数字串. 
   */ 
private long version = System.currentTimeMillis(); 
 
private long generation = 0;     // 下次提交时"segments_N"的N=generation 
private long lastGeneration = 0;   // 最后一次成功读取或者写入,"segments_N"中N=lastGeneration 
 
/** 
   * 如果索引文件不是null的,则构造一个输出流,输出segments_N文件 
   */ 
private static PrintStream infoStream; 
 
public final SegmentInfo info(int i) { 
    return (SegmentInfo) elementAt(i); 
} 
 
/** 
   * 从指定的文件列表files中获取当前segments_N文件的版本号(generation) 
   */ 
public static long getCurrentSegmentGeneration(String[] files) { 
    if (files == null) {    // 如果指定的索引目录中没有索引文件,返回-1 
      return -1; 
    } 
    long max = -1;    // 不存在任何索引文件,当默认当前版本号为-1 
    for (int i = 0; i < files.length; i++) {    // 对索引目录中所有索引文件遍历,取出segments_N中最大的N的作为当前版本号 
      String file = files[i]; 
 
// IndexFileNames.SEGMENTS="segments",segments是生成的索引文件,在IndexFileNames类中定义了所有的索引文件名 
 
// IndexFileNames.SEGMENTS_GEN="segments.gen" 
      if (file.startsWith(IndexFileNames.SEGMENTS) && !file.equals(IndexFileNames.SEGMENTS_GEN)) { 
        long gen = generationFromSegmentsFileName(file); // 调用后面的方法,获取索引文件的版本号(generation) 
        if (gen > max) { 
          max = gen; 
        } 
      } 
    } 
    return max;    //   将segments_N中最大的N返回,作为当前版本号(generation) 
} 
 
/** 
   * 重载的方法,从指定的索引目录中获取当前segments_N文件的版本号(generation) 
   */ 
public static long getCurrentSegmentGeneration(Directory directory) throws IOException { 
    String[] files = directory.list(); 
    if (files == null) 
      throw new IOException("cannot read directory " + directory + ": list() returned null"); 
    return getCurrentSegmentGeneration(files);     //调用getCurrentSegmentGeneration()方法,从索引目录中读取的文件列表files中获取当前segments_N文件的版本号(generation) 
} 
 
/** 
   * 指定索引文件列表,获取当前segments_N文件的名称 
   */ 
 
public static String getCurrentSegmentFileName(String[] files) throws IOException { 
    return IndexFileNames.fileNameFromGeneration(IndexFileNames.SEGMENTS, "",getCurrentSegmentGeneration(files));    // 调用了IndexFileNames类的fileNameFromGeneration()方法,在后面有讲解 
} 
 
/** 
   * 重载的方法,指定索引目录,获取当前segments_N文件的名称 
   */ 
public static String getCurrentSegmentFileName(Directory directory) throws IOException { 
    return IndexFileNames.fileNameFromGeneration(IndexFileNames.SEGMENTS,"", 
getCurrentSegmentGeneration(directory)); 
} 
 
  /** 
   * 重载的方法,根据索引文件的信息,即最后成功读取或写入时的版本号lastGeneration,获取当前segments_N文件的名称 
   */ 
public String getCurrentSegmentFileName() { 
    return IndexFileNames.fileNameFromGeneration(IndexFileNames.SEGMENTS,"",lastGeneration); 
} 
 
/** 
   * 从索引文件名称的字符串中解析索引文件的版本号,即segments_N中的N,并且最后返回N的值 
   */ 
public static long generationFromSegmentsFileName(String fileName) { 
    if (fileName.equals(IndexFileNames.SEGMENTS)) {    // 如果文件名称为segments,没有扩展名,则返回0 
      return 0; 
    } else if (fileName.startsWith(IndexFileNames.SEGMENTS)) { 
      return Long.parseLong(fileName.substring(1+IndexFileNames.SEGMENTS.length()),Character.MAX_RADIX);    // 取segments_N中的子串N,并将N转换为Long型 
    } else {    // 解析失败,抛出异常 
      throw new IllegalArgumentException("fileName \"" + fileName + "\" is not a segments file"); 
    } 
} 
 
 
/** 
   * 获取下一个将被写入索引目录的segments_N文件 
   */ 
public String getNextSegmentFileName() { 
    long nextGeneration; 
 
    if (generation == -1) {    // 如果当前索引目录中没有任何索引文件,则最新写入的索引文件的版本号为1,即segments_1 
      nextGeneration = 1; 
    } else { 
      nextGeneration = generation+1;   // 否则,当前的版本号+1为将要写入的索引文件的版本号 
    } 
 
    // 返回将要写入索引目录的索引文件的名称,即文件名segments_N,N用nextGeneration替换 
    return IndexFileNames.fileNameFromGeneration(IndexFileNames.SEGMENTS,"",nextGeneration); 
} 
 
/** 
   * 读取指定的索引文件 
   */ 
public final void read(Directory directory, String segmentFileName) throws CorruptIndexException, IOException { 
    boolean success = false; 
 
    IndexInput input = directory.openInput(segmentFileName);    // 为索引文件segmentFileName创建一个输入流 
 
    generation = generationFromSegmentsFileName(segmentFileName);    // 下次要提交的索引文件的版本号 
 
    lastGeneration = generation;    // 最后成功读取或写入索引文件的版本号 
 
    try { 
      int format = input.readInt();    // 读取4个字节,返回一个Int型整数,索引文件中具有版本号的记录 
      if(format < 0){     // 如果文件包含了外部的版本号 
        // 要解析成内部能够使用的信息 
        if (format < CURRENT_FORMAT)    // 如果读取到的Int整数小于当前从索引文件中获取的版本号,则是错误的 
          throw new CorruptIndexException("Unknown format version: " + format); 
        version = input.readLong(); // 读取版本号Long串 
        counter = input.readInt(); // 读取用于命名当前的索引文件的gen值 
      } 
      else{     // 索引文件没有外部格式信息,就去当前从索引文件中读取到的整数值为当前的索引文件命名 
        counter = format; 
      } 
      
      for (int i = input.readInt(); i > 0; i--) { // 读取索引段信息 
        addElement(new SegmentInfo(directory, format, input));    //   构造一个用于管理索引文件的SegmentInfo对象,添加到SegmentInfos向量列表中去 
      } 
      
      if(format >= 0){    // 对于旧格式的索引文件,版本号信息可能在文件的末尾 
        if (input.getFilePointer() >= input.length()) 
          version = System.currentTimeMillis(); // 如果旧文件格式没有版本号信息,则设置当前版本号 
        else 
          version = input.readLong(); // 否则,如果不是旧格式索引文件,直接从索引文件中读取版本号 
      } 
      success = true;    // 获取到索引文件的版本号,则标志位success置true,表示可以生成当前版本的索引文件(名称) 
    } 
    finally { 
      input.close(); 
      if (!success) { 
        clear(); 
      } 
    } 
} 
 
 
/** 
   * 如果读取索引文件失败,重新尝试再次去读取 
   */ 
public final void read(Directory directory) throws CorruptIndexException, IOException { 
 
    generation = lastGeneration = -1; 
 
    new FindSegmentsFile(directory) {    // FindSegmentsFile是一个静态抽象内部类,在此实现从索引目录中加载索引文件 
 
      protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException { 
        read(directory, segmentFileName);    // 初始化一个FindSegmentsFile的实例时,调用上面实现的读取索引文件的read方法 
        return null; 
      } 
    }.run();    //   调用继承自抽象类FindSegmentsFile的run方法进行读取,(run方法的实现比较复杂) 
} 
 
/** 
   * 执行写入当前的索引文件操作 
   */ 
 
public final void write(Directory directory) throws IOException { 
 
    String segmentFileName = getNextSegmentFileName(); 
 
    // Always advance the generation on write: 
    if (generation == -1) { 
      generation = 1; 
    } else { 
      generation++; 
    } 
 
    IndexOutput output = directory.createOutput(segmentFileName);    // 构造一个索引文件输出流 
 
    boolean success = false; 
 
    try { 
      output.writeInt(CURRENT_FORMAT); // 写入FORMAT 
      output.writeLong(++version);    // 写入版本号 
      output.writeInt(counter);    //   写入当前的索引文件的外部信息(即segment_N中的N的值) 
      output.writeInt(size());   // 写入该SegmentInfos中的每个SegmentInfo的信息 
      for (int i = 0; i < size(); i++) { 
        info(i).write(output); 
      }         
    } 
    finally { 
      try { 
        output.close();    // 关闭索引文件输出流,成功写入索引目录 
        success = true; 
      } finally { 
        if (!success) {    // 如果写入失败,执行回滚操作,删除非法的写入失败的索引文件 
          directory.deleteFile(segmentFileName); 
        } 
      } 
    } 
 
    try { 
      output = directory.createOutput(IndexFileNames.SEGMENTS_GEN);    // 创建segment.gen文件,打开一个输出文件流 
      try {    // 写入维护所需要的信息 
        output.writeInt(FORMAT_LOCKLESS); 
        output.writeLong(generation); 
        output.writeLong(generation); 
      } finally { 
        output.close(); 
      } 
    } catch (IOException e) { 
      // It's OK if we fail to write this file since it's 
      // used only as one of the retry fallbacks. 
    } 
    
    lastGeneration = generation; 
} 
 
/** 
   * 克隆一个SegmentInfos 
   */ 
 
public Object clone() { 
    SegmentInfos sis = (SegmentInfos) super.clone(); 
    for(int i=0;i<sis.size();i++) { 
      sis.setElementAt(((SegmentInfo) sis.elementAt(i)).clone(), i); 
    } 
    return sis; 
} 
 
/** 
   * SegmentInfos生成的版本号 
   */ 
public long getVersion() { 
    return version; 
} 
public long getGeneration() { 
    return generation; 
} 
 
/** 
   * 从segments文件中读取当前的版本号. 
   */ 
public static long readCurrentVersion(Directory directory) 
    throws CorruptIndexException, IOException { 
 
    return ((Long) new FindSegmentsFile(directory) { 
        protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException { 
 
          IndexInput input = directory.openInput(segmentFileName); 
 
          int format = 0; 
          long version = 0; 
          try { 
            format = input.readInt(); 
            if(format < 0){ 
              if (format < CURRENT_FORMAT) 
                throw new CorruptIndexException("Unknown format version: " + format); 
              version = input.readLong();   // read version 
            } 
          } 
          finally { 
            input.close(); 
          } 
     
          if(format < 0) 
            return new Long(version); 
 
          // We cannot be sure about the format of the file. 
          // Therefore we have to read the whole file and cannot simply seek to the version entry. 
          SegmentInfos sis = new SegmentInfos(); 
          sis.read(directory, segmentFileName); 
          return new Long(sis.getVersion()); 
        } 
      }.run()).longValue(); 
} 
 
/** 
   * segments 文件输出流 
   */ 
public static void setInfoStream(PrintStream infoStream) { 
    SegmentInfos.infoStream = infoStream; 
} 
 
/* Advanced configuration of retry logic in loading 
     segments_N file */ 
private static int defaultGenFileRetryCount = 10; 
private static int defaultGenFileRetryPauseMsec = 50; 
private static int defaultGenLookaheadCount = 10; 
 
/** 
   * Advanced: set how many times to try loading the 
   * segments.gen file contents to determine current segment 
   * generation. This file is only referenced when the 
   * primary method (listing the directory) fails. 
   */ 
public static void setDefaultGenFileRetryCount(int count) { 
    defaultGenFileRetryCount = count; 
} 
 
public static int getDefaultGenFileRetryCount() { 
    return defaultGenFileRetryCount; 
} 
 
/** 
   * Advanced: set how many milliseconds to pause in between 
   * attempts to load the segments.gen file. 
   */ 
public static void setDefaultGenFileRetryPauseMsec(int msec) { 
    defaultGenFileRetryPauseMsec = msec; 
} 
 
public static int getDefaultGenFileRetryPauseMsec() { 
    return defaultGenFileRetryPauseMsec; 
} 
 
/** 
   * Advanced: set how many times to try incrementing the 
   * gen when loading the segments file. This only runs if 
   * the primary (listing directory) and secondary (opening 
   * segments.gen file) methods fail to find the segments 
   * file. 
   */ 
public static void setDefaultGenLookaheadCount(int count) { 
    defaultGenLookaheadCount = count; 
} 
 
public static int getDefaultGenLookahedCount() { 
    return defaultGenLookaheadCount; 
} 
 
public static PrintStream getInfoStream() { 
    return infoStream; 
} 
 
private static void message(String message) { 
    if (infoStream != null) { 
      infoStream.println(Thread.currentThread().getName() + ": " + message); 
    } 
} 
 
////********这里是FindSegmentsFile抽象静态内部类的定义,可以参考Lucene实现源代码********//// 
} 


从SegmentInfos类的实现过程可以看出,该类主要是对SegmentInfo进行管理的。在每次执行打开索引目录、打开索引文件、写入文件等等,都需要对SegmentInfos进行维护。

因为SegmentInfos记录了对索引文件进行操作(如:建立索引、删除索引)而生成的一些索引文件格式、版本号的信息,所以每当索引文件有操作需求,都要从SegmentInfos中获取当前的一些详细记录,SegmentInfos是操作索引文件的依据,同时操作索引文件结束后,要及时更新 SegmentInfos的记录信息,为下次操作索引文件提供准确的信息。

SegmentInfos类主要通过两个文件来维护这些信息:segment_N和segment.gen文件。

segment_N文件存储的是当前正处于激活状态的索引文件的信息,也就是当前操作的索引文件的维护信息。

segment.gen文件是专门用于管理segment_N文件的。这里,segment_N文件是动态变化的,比如每次写入新的索引文件或者删除索引文件都涉及到当前索引文件的版本问题。segment.gen主要管理的的操作索引文件的版本信息的。

在处理提交点的时候,也要参考索引文件的版本,都需要从segment.gen中读取;根据实际的操作,还要在操作结束的时候更新segment.gen文件,保证下次操作的正确性。
分享到:
评论

相关推荐

    lucene3.0.0的学习资料

    lucene3.0.0的学习资料,里边有lucene的jar包,具体的入门讲解:http://blog.csdn.net/lengyuhong/archive/2010/11/17/6014597.aspx

    【分享:lucene学习资料】---<下载不扣分,回帖加1分,欢迎下载,童叟无欺>

    1&gt; lucene学习笔记 2&gt; 全文检索的实现机制 【1】lucene学习笔记的目录如下 1. 概述 3 2. lucene 的包结构 3 3. 索引文件格式 3 4. lucene中主要的类 4 4.1. Document文档类 4 4.1.1. 常用方法 4 4.1.2. 示例 4 4.2...

    Lucene4.X实战类baidu搜索的大型文档海量搜索系统-17.Lucene高级进阶3 共4页.pptx

    本教程通过17讲内容,深入讲解了如何利用Lucene4.X实现一个类似百度的大型文档搜索系统。在高级进阶部分,我们将重点探讨Lucene在索引、搜索、排序、过滤以及分词器等方面的高级用法,旨在帮助开发者掌握Lucene的...

    Lucene建立索引及查询包含“java”关键字 示例代码

    这个示例中的"day0217"可能是指课程或项目的编号,表示该示例代码是学习过程中的第二天第17个主题。通过这些代码,我们可以学习到Lucene的核心概念,包括索引构建、分词分析和查询执行,这对于理解全文检索系统的...

    北风网Lucene搜索引擎源码及PPT

    例如,lucene17.rar可能包含了不同版本的分析器源码,用于研究不同的文本处理策略。 3. **索引构建** Lucene通过构建倒排索引来实现快速的全文搜索。在lucene10.rar到lucene15.rar中,我们可以看到不同版本的索引...

    Lucene4.X实战类baidu搜索的大型文档海量搜索系统-03.Lucene索引里有什么 共17页.pptx

    《Lucene4.X实战类baidu搜索的大型文档海量搜索系统》课程主要涵盖了Lucene的基础概念、架构、索引原理及优化、搜索实现、实战应用等多个方面,旨在帮助学习者深入理解并掌握Lucene这一强大的全文搜索引擎库。...

    java学习过程资源

    【学习阶段17】项目二:宜立方商城(80-93天): 这是一个更大型的电商项目,涉及更多的业务逻辑和功能,能进一步提高你的全栈开发能力。 通过以上学习,你将获得全面的Java开发技能,涵盖Web开发、数据库管理、...

    java的28个学习目标

    了解并掌握常用的外部API和框架,如Log4J(日志)、Quartz(调度)、JGroups(网络组通信)、JCache(分布式缓存)、Lucene(全文检索)等。 ### 19. 跨平台与本地接口 学习跨平台开发技巧,掌握JNI(Java Native ...

    搜索引擎示例

    另一个文件“17_092125_lucene.net2.000227nov06.src”很可能是一个Lucene.NET的源代码包。Lucene是一个用Java编写的全文搜索引擎库,Lucene.NET是它的.NET版本,使得.NET开发者也能利用其强大的搜索功能。文件名中...

    Java学习的30个目标

    熟悉日志框架(如Log4J)、任务调度(如Quartz)、分布式缓存(如JCache)、全文搜索(如Lucene)等常用框架和API。 #### 21. 本地接口与连接器架构 学习Java Native Interface(JNI)和Java Connector ...

    学习java的30个目标.txt

    #### 目标17:学习企业级Java Beans(EJB) - **技术分类**:无状态会话Bean、有状态会话Bean、实体Bean、消息驱动Bean等。 - **开发技巧**:理解Bean-Managed Persistence(BMP)与Container-Managed Persistence...

    学习Java语言的30个参考,让你坐拥别人之上的30个擦考

    - **Lucene**:学习全文检索技术的基础知识。 ### 21. 本地接口与连接器 - **JNI、JCA**:掌握Java Native Interface、Java Connector Architecture等技术,实现Java与其他语言或平台的交互。 通过以上知识点的...

    java学习目标

    #### 17. JINI与CORBA 熟悉JINI和CORBA等分布式计算协议,可以增强应用的网络通信能力和互操作性。 以上目标不仅涵盖了Java语言本身的学习,还涉及了从设计模式、架构原则到具体框架和工具的广泛领域。通过达成...

    传智播客Javaweb课件大全ppt 第二部分

    【传智播客Javaweb课件大全ppt 第二部分】是一套全面涵盖Java Web技术的教育资源,适合初学者和有一定基础的学习者深入理解这一领域。本课件集合包括了多个不同主题的文档和图片,旨在帮助学习者掌握Java Web开发的...

    java的30个学习目标

    #### 17. **XML处理** - JAXP、JDOM、DOM4J、JAXR等API用于解析、生成和操作XML文档。 #### 18. **Web服务** - JAX-RPC、SAAJ、JAXB、JAXM、JAXR等技术用于构建和消费Web服务。 #### 19. **依赖注入(DI/IoC)** ...

    搜索引擎开发培训课程提纲PPT学习教案.pptx

    17. **自动摘要**:自动摘要技术用于生成文档的简短概述,基于机器学习的方法如TextRank可以实现这一目标。 18. **自动分类**:SVM等分类算法可用于自动分类文档,多级分类可以进一步细化分类体系。 19. **自动...

    《ElasticSearch入门到实战》电子书,从入门到进阶实战项目的教程文档,框架SpringBoot框架整合ES.zip

    Elasticsearch 是一个基于 Lucene 的开源全文搜索引擎,以其分布式、可扩展性、实时搜索以及强大的数据分析能力而受到广泛欢迎。它不仅支持文本搜索,还可以处理结构化和非结构化数据,适用于日志分析、监控、信息...

    金融网站源码

    系统采用Spring + hibernate ,整合shiro 权限,lucene,activiti,多个技术的金融综合系统 前后端完整,eclipse开发 ,网站17年运营后关闭 ,该部分代码于项目上线中期开发段代码 ,推荐学习使用

    收集java学习资料和面试题包括git上好的项目

    ##### 17. Quartz - **简介**:一个强大的、开放源代码的任务调度框架。 - **链接**:[http://www.quartz-scheduler.org/](http://www.quartz-scheduler.org/) - **核心特性**: - 任务调度 - 定时执行 - 触发器...

    elasticsearch-7.17.7-windows-x86-64.zip

    9. **X-Pack插件**:Elastic公司提供的X-Pack插件,包括监控、警报、安全管理、机器学习等功能,为Elasticsearch提供了更全面的企业级特性。 10. **安装与配置**:解压"elasticsearch-7.17.7"文件后,用户需按照...

Global site tag (gtag.js) - Google Analytics