复合索引文件格式cfs

Lucene-2.3.1 源代码阅读学习 立即下载

来自:http://www.cnblogs.com/lvpei/articles/1731848.html

复合索引文件格式(.cfs)是如何产生的?从这个问题出发,研究索引文件是如何合并的,这都是IndexWriter类中定义的一些重要的方法。

在建立索引过程中,生成的索引文件的格式有很多种。

在文章 Lucene-2.2.0 源代码阅读学习(4) 中测试的那个例子,没有对IndexWriter进行任何的客户化设置,完全使用Lucene 2.2.0默认的设置(以及,对Field的设置使用了Lucene自带的Demo中的设置)。

运行程序以后,在本地磁盘的索引目录中生成了一些.扩展名为.cfs的索引文件,即复合索引格式文件。如图(该图在文章 Lucene-2.2.0 源代码阅读学习(4) 中介绍过)所示:

从上面生成的那些.cfs复合索引文件可以看出,Lucene 2.2.0版本,IndexWriter索引的一个成员useCompoundFile的设置起了作用,可以在IndexWriter类的内部看到定义和默认设置:

private boolean useCompoundFile = true;

即,默认使用复合索引文件格式来存储索引文件。

在IndexWriter类的addDocument(Document doc, Analyzer analyzer)方法中可以看到,最后调用了 maybeFlushRamSegments()方法,这个方法的作用可是很大的,看它的定义:

protected final void maybeFlushRamSegments() throws CorruptIndexException, IOException {
    if (ramSegmentInfos.size() >= minMergeDocs || numBufferedDeleteTerms >= maxBufferedDeleteTerms) {
      flushRamSegments();
    }
}

这里,minMergeDocs是指:决定了合并索引段文件时指定的最小的Document的数量,在IndexWriter类中默认值为10,可以在IndexWriter类中查看到:

     private int minMergeDocs = DEFAULT_MAX_BUFFERED_DOCS;
   public final static int DEFAULT_MAX_BUFFERED_DOCS = 10;

其中SegmentInfos ramSegmentInfos中保存了Document的数量的信息,如果Document的数量小于10,则调用flushRamSegments()方法进行处理,flushRamSegments()方法的定义如下所示:

private final synchronized void flushRamSegments() throws CorruptIndexException, IOException {
    flushRamSegments(true);
}

在flushRamSegments()方法中又调用到了该方法的一个重载的方法,带一个boolean型参数。该重载的方法定义如下:

protected final synchronized void flushRamSegments(boolean triggerMerge) 
      throws CorruptIndexException, IOException {
    if (ramSegmentInfos.size() > 0 || bufferedDeleteTerms.size() > 0) {
      mergeSegments(ramSegmentInfos, 0, ramSegmentInfos.size());
      if (triggerMerge) maybeMergeSegments(minMergeDocs);
    }
}

同样,如果Document的数量小于10,则调用mergeSegments()方法,先看一下该方法的参数:

private final int mergeSegments(SegmentInfos sourceSegments, int minSegment, int end)

第一个参数指定了一个SegmentInfos(上面调用传递了ramSegmentInfos) ;第二个参数是minSegment是最小的索引段数量(上面调用传递了0,说明如果存在>=0个索引段文件时就开始合并索引文件);第三个参数是end,指要合并索引段文件的个数(上面调用传递了ramSegmentInfos.size(),即对所有的索引段文件都执行合并操作)。

继续看mergeSegments()方法的实现:

private final int mergeSegments(SegmentInfos sourceSegments, int minSegment, int end)
    throws CorruptIndexException, IOException {

    // doMerge决定了是否执行合并操作,根据end的值,如果end为0说明要合并的索引段文件为0个,即不需要合并,doMerge=false
    boolean doMerge = end > 0;

/*    生成合并的索引段文件名称,即根据SegmentInfos的counter值,如果counter=0,则返回的文件名为_0(没有指定扩展名)

    final synchronized String newSegmentName() {
        return "_" + Integer.toString(segmentInfos.counter++, Character.MAX_RADIX);
    }

*/
    final String mergedName = newSegmentName();
    SegmentMerger merger = null;   // 声明一个SegmentMerger变量

    final List ramSegmentsToDelete = new ArrayList();    // ramSegmentsToDelete列表用于存放可能要在合并结束后删除的索引段文件,因为合并的过程中需要删除掉合并完以后存在于内存中的这些索引段文件

    SegmentInfo newSegment = null;

    int mergedDocCount = 0;
    boolean anyDeletes = (bufferedDeleteTerms.size() != 0);

    // This is try/finally to make sure merger's readers are closed:
    try {

      if (doMerge) {    // 如果doMerge=true,即end>0,也就是说至少有1个以上的索引段文件存在,才能谈得上合并
        if (infoStream != null) infoStream.print("merging segments");    // infoStream是一个PrintStream输出流对象,合并完成后要向索引目录中写入合并后的索引段文件,必须有一个打开的输出流
        merger = new SegmentMerger(this, mergedName);    // 构造一个SegmentMerger对象,通过参数:当前的打开的索引器this和合并后的索引段名称mergedName(形如_N,其中N为数)关于SegmentMerger类会在后面文章学习

        for (int i = minSegment; i < end; i++) {    // 循环遍历,从SegmentInfos sourceSegments中迭代出每个SegmentInfo对象
          SegmentInfo si = sourceSegments.info(i);
          if (infoStream != null)
            infoStream.print(" " + si.name + " (" + si.docCount + " docs)");    // SegmentInfo si的name在索引目录中是唯一的;这里打印出每个 SegmentInfo si的名称和在这个索引段文件中Document的数量
          IndexReader reader = SegmentReader.get(si, MERGE_READ_BUFFER_SIZE);   // 调用SegmentReader类的静态方法get(),根据每个SegmentInfo si获取一个索引输入流对象;在IndexWriter类中定义了成员MERGE_READ_BUFFER_SIZE=4096
          merger.add(reader);    //   将获取到的SegmentReader reader加入到SegmentMerger merger中
          if (reader.directory() == this.ramDirectory) {    // 如果SegmentReader reader是当前的索引目录,与当前的RAMDirectory ramDirectory是同一个索引目录
            ramSegmentsToDelete.add(si);    // 将该SegmentInfo si加入到待删除的列表ramSegmentsToDelete中
          }
        }
      }

      SegmentInfos rollback = null;
      boolean success = false;

      // This is try/finally to rollback our internal state
      // if we hit exception when doing the merge:
      try {

        if (doMerge) {     // 如果doMerge=true
          mergedDocCount = merger.merge();    // 通过SegmentMerger merger获取需要合并的索引段文件数量

          if (infoStream != null) {    // 打印出合并后的索引段文件的名称,及其合并了索引段文件的数量
            infoStream.println(" into "+mergedName+" ("+mergedDocCount+" docs)");
          }

          newSegment = new SegmentInfo(mergedName, mergedDocCount,
                                       directory, false, true);    // 实例化一个SegmentInfo对象
        }
        
        if (sourceSegments != ramSegmentInfos || anyDeletes) {
          // 通过克隆,存储一个用来回滚用的SegmentInfos实例,以防合并过程中发生异常
          rollback = (SegmentInfos) segmentInfos.clone();
        }

        if (doMerge) {   // 如果doMerge=true
          if (sourceSegments == ramSegmentInfos) {   // 如果传进来的sourceSegments和内存中的ramSegmentInfos是同一个
            segmentInfos.addElement(newSegment);    // 将合并后的新的SegmentInfo newSegment加入到segmentInfos中进行管理,以便之后再对其操作
          } else { // 如果传进来的sourceSegments和内存中的ramSegmentInfos不是同一个
            for (int i = end-1; i > minSegment; i--)     // 删除旧的信息,同时添加新的信息
              sourceSegments.remove(i);

            segmentInfos.set(minSegment, newSegment);
          }
        }

        if (sourceSegments == ramSegmentInfos) {    // 如果传进来的sourceSegments和内存中的ramSegmentInfos是同一个,因为参数设置的原因,可能需要删除合并以后原来旧的索引段文件
          maybeApplyDeletes(doMerge);    // 调用 maybeApplyDeletes()方法执行合并后的删除处理
          doAfterFlush();
        }
        
        checkpoint();   // 调用该方法 checkpoint()检查,确认并提交更新

        success = true;    // 如果检查没有发现异常,则置success=true

      } finally {

        if (success) {    // 如果success=true,表示提交成功,要清理内存
          if (sourceSegments == ramSegmentInfos) {
            ramSegmentInfos.removeAllElements();
          }
        } else {    // 如果发生异常,则需要回滚操作

          if (sourceSegments == ramSegmentInfos && !anyDeletes) {
            if (newSegment != null && 
                segmentInfos.size() > 0 && 
                segmentInfos.info(segmentInfos.size()-1) == newSegment) {
              segmentInfos.remove(segmentInfos.size()-1);
            }
          } else if (rollback != null) {
            segmentInfos.clear();
            segmentInfos.addAll(rollback);
          }

          // Delete any partially created and now unreferenced files:
          deleter.refresh();
        }
      }
    } finally {
      // 关闭所有的输入流(readers),尝试删除过时的废弃文件
      if (doMerge) merger.closeReaders();
    }

    // 删除RAM中的索引段文件
    deleter.deleteDirect(ramDirectory, ramSegmentsToDelete);

    // 一个检查点,允许一个IndexFileDeleter deleter有机会在该时间点上去删除文件
    deleter.checkpoint(segmentInfos, autoCommit);

    if (useCompoundFile && doMerge) {   // 如果IndexWriter索引器设置了useCompoundFile=true

      boolean success = false;

      try {

        merger.createCompoundFile(mergedName + ".cfs");    //   创建复合索引文件(.cfs),即_N.cfs文件
        newSegment.setUseCompoundFile(true);    // 设置SegmentInfo newSegment为复合索引文件的信息
        checkpoint();      // 调用该方法 checkpoint()检查,确认并提交更新
        success = true;

      } finally {    // 如果检查过程中发生异常,则回滚
        if (!success) {  
          newSegment.setUseCompoundFile(false);
          deleter.refresh();
        }
      }
      
     // 一个检查点,允许一个IndexFileDeleter deleter有机会在该时间点上去删除文件
      deleter.checkpoint(segmentInfos, autoCommit);
    }

    return mergedDocCount; // 返回需合并的索引段文件数量
}

 

 

 

 

 

 

 

 

 

在不带参数的flushRamSegments()方法中,调用了带参数的flushRamSegments(boolean triggerMerge),也就是说,默认情况下,Lucene指定triggerMerge=true,可以在不带参数的flushRamSegments()方法中看到对该参数的设置:

private final synchronized void flushRamSegments() throws CorruptIndexException, IOException {
    flushRamSegments(true);
}

所以,在带参数的flushRamSegments(boolean triggerMerge)方法中,一定会执行maybeMergeSegments()这个合并索引的方法,如下所示:

if (triggerMerge) maybeMergeSegments(minMergeDocs);

这里,传递的参数minMergeDocs=10(Lucene默认值),那么就应该有一个maxMergeDocs的成员与之对应,在Lucene 2.2.0版本中,在IndexWriter类中定义了该maxMergeDocs成员的默认值:

    private int maxMergeDocs = DEFAULT_MAX_MERGE_DOCS;
    public final static int DEFAULT_MAX_MERGE_DOCS = Integer.MAX_VALUE;
    public static final int   MAX_VALUE = 0x7fffffff;

maxMergeDocs是合并的最大的Document的数量,定义为最大的Integer。

因为一个索引目录中的索引段文件的数量可能大于minMergeDocs=10,如果也要对所有的索引段文件进行合并,则指定合并最小数量minMergeDocs的Docment是不能满足要求的,即使用mergeSegments()方法。

因此,maybeMergeSegments()就能实现合并性能的改善,它的声明就是需要一个起始的参数,从而进行增量地合并索引段文件。该方法的实现如下所示:

/** Incremental segment merger. */
private final void maybeMergeSegments(int startUpperBound) throws CorruptIndexException, IOException {
    long lowerBound = -1;
    long upperBound = startUpperBound;    // 使用upperBound存放传递进来的startUpperBound

    while (upperBound < maxMergeDocs) {    // 如果upperBound < maxMergeDocs,一般来说,这个应该总成立的
      int minSegment = segmentInfos.size();    //   设置minSegment的值为当前的SegmentInfos segmentInfos 的大小
      int maxSegment = -1;

      // 查找能够合并的索引段文件
      while (--minSegment >= 0) {    // 就是遍历SegmentInfos segmentInfos中的每个SegmentInfo si
        SegmentInfo si = segmentInfos.info(minSegment);    // 从索引位置号最大的开始往外取

        if (maxSegment == -1 && si.docCount > lowerBound && si.docCount <= upperBound) {    // maxSegment == -1;同时满足-1=lowerBound <(一个索引段文件中Dcoment的数量si.docCount)<=upperBound = startUpperBound
          // start from the rightmost* segment whose doc count is in bounds
          maxSegment = minSegment;    //   设置maxSegment的值为当前SegmentInfos的大小
        } else if (si.docCount > upperBound) {
          // 直到segment中Document的数量超过了上限upperBound,则退出循环
          break;
        }
      }

    // 该while循环只执行了一次,执行过程中,将maxSegment赋值为segmentInfos.size()-1

      minSegment++;    // 上面循环中一直执行--minSegment,则到这里minSegment=-1,设置其值为0 
      maxSegment++;    // 因为maxSegment=segmentInfos.size()-1,则设置为maxSegment=segmentInfos.size()
      int numSegments = maxSegment - minSegment;    // numSegments = maxSegment - minSegment = segmentInfos.size()  

      if (numSegments < mergeFactor) {

    /* mergeFactor是合并因子,IndexWriter的成员,默认设置为10,mergeFactor的值越大,则内存中驻留的Document就越多,向索引目录中写入segment的次数就越少,虽然占用内存较多,但是速度应该很快的。每向索引文件中加入mergeFactor=10个Document的时候,就会在索引目录中生成一个索引段文件(segment) */
        break;    // numSegments < mergeFactor则没有达到合并所需要的数量,不需要合并,直接退出
      } else {
        boolean exceedsUpperLimit = false;    // 设置一个没有超过上限的boolean型标志(false)

        // 能够合并的segments的数量>=mergeFactor时
        while (numSegments >= mergeFactor) {
          // 调用mergeSegments(即上面的学习到的那个合并的方法)方法,合并从minSegment开始的mergeFactor个segment

          int docCount = mergeSegments(segmentInfos, minSegment, minSegment + mergeFactor);
          numSegments -= mergeFactor; // mergeFactor个segment已经合并完成,剩下需要合并的数量要减去mergeFactor,在下一次循环的时候继续合并

          if (docCount > upperBound) {    // 如果上次合并返回的合并后的Document的数量大于上限
            // 继续在该层次合并剩余的segment
            minSegment++;
            exceedsUpperLimit = true;    //   设置已经超过上限,不能再进行深一层次的的合并,即本轮合并就是最深层次的合并了
          } else { // 如果上次合并返回的合并后的Document的数量没有超过上限
            // 考虑进行更深层次的合并
            numSegments++;
          }
        }

        if (!exceedsUpperLimit) {// 如果上次合并返回的合并后的Document的数量大于上限,则终止执行本层次合并
          break;
        }
      }

      lowerBound = upperBound;
      upperBound *= mergeFactor;    // 如果一个层次的合并成功后,还可以进一步合并,则,上限变为原来的10倍
    }
}

合并索引段文件就是这样实现的,并非只是在一个层次上合并:

第一层次合并时,每次只能将10个segment索引段文件合并为1个新的segment,假设在这一层生成了500个经过合并以后生成的索引段文件;

第二层次合并时,每次能合并10*mergeFactor=10*10=100个segment,经判断,上一层次生成了500个segment还可以进行第二层次的合并,现在每次100个segment文件才可能合并为1个,可见,只能合并生成5个新的segment;

第三层次合并时,每次能合并10*mergeFactor*mergeFactor=10*10*10=1000个segment,但是上一层次只是生成了5个,不够数量(1000个),不能继续合并了,到此终止。

就是上面的那种原理,实现索引段文件的合并。如果希望进行更深层次的合并,把mergeFactor的值设置的非常小就可以了,但是I/O操作过于频繁,速度会很慢很慢的。

提高合并的速度,是以内存空间开销为代价的。

通过第一个合并的方法可以看出,只有当为一个IndexWriter索引器设置了useCompoundFile=true的时候,才能生成复合索引文件_N.cfs,如下所示:

    if (useCompoundFile && doMerge) {   // 如果IndexWriter索引器设置了useCompoundFile=true

      boolean success = false;

      try {

        merger.createCompoundFile(mergedName + ".cfs");    //   创建复合索引文件(.cfs),即_N.cfs文件
        newSegment.setUseCompoundFile(true);    // 设置SegmentInfo newSegment为复合索引文件的信息
        checkpoint();      // 调用该方法 checkpoint()检查,确认并提交更新
        success = true;

      } finally {    // 如果检查过程中发生异常,则回滚
        if (!success) {  
          newSegment.setUseCompoundFile(false);
          deleter.refresh();
        }
      }
      
     // 一个检查点,允许一个IndexFileDeleter deleter有机会在该时间点上去删除文件
      deleter.checkpoint(segmentInfos, autoCommit);
    }

现在知道了,那些_N.cfs文件是合并的索引段文件。


Lucene_原理与代码分析完整版 lucene 源码分析 立即下载

相关推荐

RK3588 EVB开发板原理图讲解【六】

该原理图展示了eMMC Flash与主控芯片之间的连接关系,以及相关的电源、信号线路和去耦电容等。

weixin_48721556的博客 1162

Lucene:(一)建立索引文件:1。复合文件

Lucene索引复合文件 Lucene的索引文件有多个文件组成,包括记载域信息的文件、segment信息的文件、term信息的文件;Lucene将这些文件复合起来存储; 这里将阐述以下概念: ①Directory:索引字典,Lucene自定义概念,如同现实中的字典存放词语一样,该字典存放文件;字典的操作包括向字典中添加文件,删除文件等。 ②合并...

weixin_30779691的博客 158

DRAM知识整理系列(三):部分时序参数整理

一、tCL-tRCD-tRP-tRAS(第一时序) 内存是根据行和列寻址的,当请求触发后,最初是tRAS(Active to precharge Delay),预充电后,内存才真正开始初始化RAS(Row Address Strobe)。一旦tRAS激活后,RAS开始进行需要数据的寻址。首先是行地址,然后初始化tRCD(RAS to CAS Delay),周期结束,接着通过CAS(Column Address Strobe)访问所需数据的十六进制地址。其中,从CAS开始到CAS结束,就是CAS延迟(即t

不吃鱼的猫的博客 7万+

符合索引格式 .cfs(参考上一篇博客)

这篇博客的内容和上一篇内容的区别不是很大,但是却是两个方向的, 这里的连接是上一个博客的, http://blog.youkuaiyun.com/u012965373/article/details/44493541 区别在于这篇的一条代码: writer.setUseCompoundFile(true); 这条代码的意思是是否使用符合的索引。 .csf文件的内容:

杨鑫newlife的专栏 1556

Excel VBA--按某一列拆分数据到多个文件

首先,将需要拆分的sheet命名为“明细”,接下来运行此代码,按提示操作即可。 在这里插入代码片 Sub chaifen() '定义变量类型 Dim sht, sh1, sh2 As Worksheet Dim k, i, j As Integer Dim irow As Integer Dim col As Integer Dim str As String '程序开始是要求输入按哪一列拆分数...

weixin_43650026的博客 5871

affymatrix探针转换 | GPL5175探针对应的基因转换

一般情况下,有一些比较成熟的对应平台的注释数据集的R包。但是这个注释平台,我在Bioconductor上找了一圈都没有找到。只能通过最原始也最可靠的方法,从GEO数据集上去下载这部分的注释文件。以下展示全过程。 我要检查的数据平台是:GPL5157。 数据集的注释集链接为:https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GPL5175 这个注释数据集比较难弄的地方在于,它的基因集注释的不太好。没有比较直接的可供提取的genesample的信息;在ge.

weixin_40640700的博客 7123

Lucene-2.2.0 源代码阅读学习(25)

复合索引文件格式(.cfs)是如何产生的?从这个问题出发,研究索引文件是如何合并的,这都是IndexWriter类中定义的一些重要的方法。 在建立索引过程中,生成的索引文件的格式有很多种。 在文章 Lucene-2.2.0 源代码阅读学习(4) 中测试的那个例子,没有对IndexWriter进行任何的客户化设置,完全使用Lucene 2.2.0默认的设置(以及,对Field的设置使用了Lucene...

pavel0的专栏 269

OpenBCI脑电帽硬件DIY与低成本搭建实战

本文详细介绍了如何通过第三方兼容硬件和开源设计,低成本DIY一套功能完备的OpenBCI脑电采集系统。从硬件选购、组装、软件配置到信号调试,提供了完整的实战指南,将总成本控制在千元级别,使脑机接口技术对爱好者、学生和研究者变得更加触手可及。

weixin_29322855的博客 785

Lucene 7.5.0 索引文件之cfs&&cfe

索引文件.cfs、.cfe被称为复合(compound)索引文件,在IndexWriterConfig可以配置是否生成复合索引文件,默认开启。   在前面的文章中,我们介绍了其他的索引文件,而复合索引文件则是将这些索引文件的数据组合到一个文件中,这种设计的目的是为了减少文件描述符的使用。   正如上文中描述的那样,复合文件实质是索引文件的组合,意思是无论是否设置了使用复合文件,总是先生成非复合...

q364367207的专栏 2439

华为OD新系统机试真题 - 失灵的键盘(C/C++/Py/Java/Js/Go)

华为OD新系统机试真题 【失灵的键盘】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD4月15号机试真题【失灵的键盘】

qq_45776114的博客 1064

YOLOv11 环境配置全流程 | 从零开始搭建训练与推理环境

YOLOv11环境配置与训练全流程指南 本文详细介绍了YOLOv11目标检测模型的环境配置、训练与推理全流程。内容包括: 环境要求:列出GPU、CUDA、Python等组件的版本要求,提供快速检查脚本 Windows配置: CUDA 12.6和cuDNN 8.9.7安装步骤 使用Conda创建隔离环境 PyTorch GPU版本安装方法 IDE环境配置 Linux配置:提供Ubuntu 22.04下的CUDA、cuDNN安装命令和Conda环境搭建 Docker方案:提供一键式容器化部署命令 训练实战: 数

shrgegrb的博客 2011

lucene学习资料(索引文件格式详解)

lucene学习资料(索引文件格式详解) 本文介绍lucene中segment,.fnm,.fdx,.fdt,.tii,.tis,deletable ,.cfs等格式文件的用途。 1。索引的segment 每个segment代表lucene的一个完整索引段。通常,在一个索引中,会包含有多个segment。每个segment都有一个统一的前缀,这个前缀是根据当前索引的docum

不了了之专栏 897

深度测评:Accio Work——目前普通用户最友好的多 Agent 协同工具

摘要:Accio Work是阿里国际站推出的多Agent协同工具,通过借鉴古代"三省六部制"构建高效协作框架。该工具支持主流大模型,可配置专业Agent角色,实现40分钟内完成复杂产品PRD等高效协作。其亮点在于直观的UI设计和流程驱动机制,能强制各Agent从专业视角深度思考。虽然超长对话稳定性有待优化,但作为目前最用户友好的多Agent工具,显著降低了构建复杂AI团队的门槛,成为提升个人和小微企业生产力的利器。

Maynor的博客 1726

Lucene 中 .fdx 和 .fdt 和.tis和.tii 还有.cfs含义

1、 .fdx 和 .fdt是使用综合的两个文件,其中.fdt用于存储具有Store.YES属性的Field的数据 而.fdt则是一个索引,用于存储Document在.fdt中的位置。 2、 .tis文件用于存储分词后的词条(Term), 而.tii就是它的索引文件,它标明了每个.tis文件中的词条位置。 3、 .cfs(复合索引格式): 在IndexWriter总有一个属性:use

杨鑫newlife的专栏 3249

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

lucene产生的索引文件格式详解

这个是lucene创建索引产生的文件,截图如下所示: 1.索引的segment 每个segment代表lucene的一个完整索引段。通常,在一个索引中,会包含有多个segment。每个segment都有一个统一的前缀,这个前缀是根据当前索引的document数量而确立的。前缀名是Document数量转为36进制后,在前面加上下划线“_”而构成的。 通常,在一个完整的索

张鹏@记忆碎片 1063

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Lucene 入门手册

lucene文件格式分析  核心提示:segment每个segment代表lucene一个完整的索引段。通常一个索引中包含了多个segment。每个segment都有统一的前缀,前缀名由Document的数量转成36进制后,在前面加“_”而构成的。通常一个完整索引中,有且只有一个没有后缀名的segment文件,它记录了当前索引中所有的s... segment 每个segment代表l...

zbmartin的博客 170

lucene 索引文件格式

 lucene索引文件格式详解本文介绍lucene中segment,.fnm,.fdx,.fdt,.tii,.tis,deletable,.cfs等格式文件的用途。 1。索引的segment每个segment代表lucene的一个完整索引段。通常,在一个索引中,会包含有多个segment。每个segment都有一个统一的前缀,这个前缀是根据当前索引的document数量而确立的

carryoutvip的专栏 828

Lucene文件格式和索引过程分析

http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661439.html

一个专注于电子商务的人的唧唧歪歪 740

lucene索引文件格式详解

lucene索引文件格式详解   本文介绍lucene中segment,.fnm,.fdx,.fdt,.tii,.tis,deletable ,.cfs等格式文件的用途。 1。索引的segment 每个segment代表lucene的一个完整索引段。通常,在一个索引中,会包含有多个segment。每个segment都有一个统一的前缀,这个前缀是根据当前索引的document数量而确立的...

cc752184245的专栏 338

Lucene6入门教程(四)索引文件格式

Lucene6(四)索引文件格式 要想要理解Lucene6关键还是要对索引的文件格式有所理解的,这是因为,了解到索引文件的格式,有助于深入理解Lucene6的两大功能——索引(全文搜索中倒排写成这个文件格式),搜索(在按文件格式将索引读取)。 可以查看Lucene6中Reader和Writer这两个类包,来更加深入地了解Lucene的文件格式,以及那些文件格式的写入和读取过程。 索引文

大漠帝国的博客 3422

Lucene 索引文件格式详解

1.索引的SEGMENT 每个SEGMENT代表LUCENE的一个完成的索引段,通常,在一个索引中,会包含多个SEGMENT,每个SEGMENT都有统一的前缀,这个前缀是根据当前索引的DOCUMENT的数量而确立的。前缀名是DOCUMENT转成36进制后在前面加“_"组成。 通常在以个完成的索引中,只有一个SEGMENT文件。这个文件没有后缀,他记录了当前索引中所有的SEGMENT信息...

baobeituping的专栏 227

Lucene文件格式简介

1、定义 Lucene中基本的概念包括index、document、field、term。 一个index包含一系列的documents; 一个document包含一系列的fields; 一个field包含一系列的terms; 一个term是一系列的bytes; 2、分段 Lucene索引可能由多个分段(segment)组成,每个分段是完全独立的,可以独立的执行搜索。有两种情况产生新的...

走向程序的康庄大道 1008

Lucene-2.3.1 源代码阅读学习(25)

复合索引文件格式(.cfs)是如何产生的?从这个问题出发,研究索引文件是如何合并的,这都是IndexWriter类中定义的一些重要的方法。 在建立索引过程中,生成的索引文件的格式有很多种。 在文章 Lucene-2.2.0 源代码阅读学习(4) 中测试的那个例子,没有对IndexWriter进行任何的客户化设置,完全使用Lucene 2.2.0默认的设置(以及,对Field的设置使用了...

wjboy49的专栏 144
上一篇: Lucene 优化
下一篇: 深入Lucene的索引文件
ArvinStudy
博客等级 码龄15年 83粉丝 193原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值