转自:http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623599.html

上面曾经交代过,Lucene保存了从Index到Segment到Document到Field一直到Term的正向信息,也包括了从Term到Document映射的反向信息,还有其他一些Lucene特有的信息。下面对这三种信息一一介绍。

4.1. 正向信息

Index –> Segments (segments.gen, segments_N) –> Field(fnm, fdx, fdt) –> Term (tvx, tvd, tvf)

上面的层次结构不是十分的准确,因为segments.gen和segments_N保存的是段(segment)的元数据信息(metadata),其实是每个Index一个的,而段的真正的数据信息,是保存在域(Field)和词(Term)中的。

4.1.1. 段的元数据信息(segments_N)

一个索引(Index)可以同时存在多个segments_N(至于如何存在多个segments_N,在描述完详细信息之后会举例说明),然而当我们要打开一个索引的时候,我们必须要选择一个来打开,那如何选择哪个segments_N呢?

Lucene采取以下过程:

  • 其一,在所有的segments_N中选择N最大的一个。基本逻辑参照SegmentInfos.getCurrentSegmentGeneration(File[] files),其基本思路就是在所有以segments开头,并且不是segments.gen的文件中,选择N最大的一个作为genA。
  • 其二,打开segments.gen,其中保存了当前的N值。其格式如下,读出版本号(Version),然后再读出两个N,如果两者相等,则作为genB。

  • IndexInput genInput = directory.openInput(IndexFileNames.SEGMENTS_GEN);//"segments.gen" 
    int version = genInput.readInt();//读出版本号 
    if (version == FORMAT_LOCKLESS) {//如果版本号正确 
        long gen0 = genInput.readLong();//读出第一个N 
        long gen1 = genInput.readLong();//读出第二个N 
        if (gen0 == gen1) {//如果两者相等则为genB 
            genB = gen0; 
        } 
    }

  • 其三,在上述得到的genA和genB中选择最大的那个作为当前的N,方才打开segments_N文件。其基本逻辑如下:

    if (genA > genB) 
        gen = genA; 
    else 
        gen = genB;

如下图是segments_N的具体格式:

  • Format:

    • 索引文件格式的版本号。
    • 由于Lucene是在不断开发过程中的,因而不同版本的Lucene,其索引文件格式也不尽相同,于是规定一个版本号。
    • Lucene 2.1此值-3,Lucene 2.9时,此值为-9。
    • 当用某个版本号的IndexReader读取另一个版本号生成的索引的时候,会因为此值不同而报错。
  • Version:
    • 索引的版本号,记录了IndexWriter将修改提交到索引文件中的次数。
    • 其初始值大多数情况下从索引文件里面读出,仅仅在索引开始创建的时候,被赋予当前的时间,已取得一个唯一值。
    • 其值改变在IndexWriter.commit->IndexWriter.startCommit->SegmentInfos.prepareCommit->SegmentInfos.write->writeLong(++version)
    • 其初始值之所最初取一个时间,是因为我们并不关心IndexWriter将修改提交到索引的具体次数,而更关心到底哪个是最新的。IndexReader中常比较自己的version和索引文件中的version是否相同来判断此IndexReader被打开后,还有没有被IndexWriter更新。

//在DirectoryReader中有一下函数。

public boolean isCurrent() throws CorruptIndexException, IOException { 
  return SegmentInfos.readCurrentVersion(directory) == segmentInfos.getVersion(); 
}

  • NameCount

    • 是下一个新段(Segment)的段名。
    • 所有属于同一个段的索引文件都以段名作为文件名,一般为_0.xxx, _0.yyy,  _1.xxx, _1.yyy ……
    • 新生成的段的段名一般为原有最大段名加一。
    • 如同的索引,NameCount读出来是2,说明新的段为_2.xxx, _2.yyy

  • SegCount

    • 段(Segment)的个数。
    • 如上图,此值为2。
  • SegCount个段的元数据信息:
    • SegName

      • 段名,所有属于同一个段的文件都有以段名作为文件名。
      • 如上图,第一个段的段名为"_0",第二个段的段名为"_1"
    • SegSize
      • 此段中包含的文档数
      • 然而此文档数是包括已经删除,又没有optimize的文档的,因为在optimize之前,Lucene的段中包含了所有被索引过的文档,而被删除的文档是保存在.del文件中的,在搜索的过程中,是先从段中读到了被删除的文档,然后再用.del中的标志,将这篇文档过滤掉。
      • 如下的代码形成了上图的索引,可以看出索引了两篇文档形成了_0段,然后又删除了其中一篇,形成了_0_1.del,又索引了两篇文档形成_1段,然后又删除了其中一篇,形成_1_1.del。因而在两个段中,此值都是2。

IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED); 
writer.setUseCompoundFile(false); 
indexDocs(writer, docDir);//docDir中只有两篇文档

//文档一为:Students should be allowed to go out with their friends, but not allowed to drink beer.

//文档二为:My friend Jerry went to school to see his students but found them drunk which is not allowed.

writer.commit();//提交两篇文档,形成_0段。

writer.deleteDocuments(new Term("contents", "school"));//删除文档二 
writer.commit();//提交删除,形成_0_1.del 
indexDocs(writer, docDir);//再次索引两篇文档,Lucene不能判别文档与文档的不同,因而算两篇新的文档。 
writer.commit();//提交两篇文档,形成_1段 
writer.deleteDocuments(new Term("contents", "school"));//删除第二次添加的文档二 
writer.close();//提交删除,形成_1_1.del

DelGen

  • .del文件的版本号
  • Lucene中,在optimize之前,删除的文档是保存在.del文件中的。
  • 在Lucene 2.9中,文档删除有以下几种方式:
    • IndexReader.deleteDocument(int docID)是用IndexReader按文档号删除。
    • IndexReader.deleteDocuments(Term term)是用IndexReader删除包含此词(Term)的文档。
    • IndexWriter.deleteDocuments(Term term)是用IndexWriter删除包含此词(Term)的文档。
    • IndexWriter.deleteDocuments(Term[] terms)是用IndexWriter删除包含这些词(Term)的文档。
    • IndexWriter.deleteDocuments(Query query)是用IndexWriter删除能满足此查询(Query)的文档。
    • IndexWriter.deleteDocuments(Query[] queries)是用IndexWriter删除能满足这些查询(Query)的文档。

lucene正向索引——正向信息,Index –> Segments (segments.gen, segments_N) –> Field(fnm, fdx, fdt) –> Term (tvx, tvd, tvf)的更多相关文章

  1. Lucene学习总结之三:Lucene的索引文件格式(1)

    Lucene的索引里面存了些什么,如何存放的,也即Lucene的索引文件格式,是读懂Lucene源代码的一把钥匙. 当我们真正进入到Lucene源代码之中的时候,我们会发现: Lucene的索引过程, ...

  2. Lucene学习之四:Lucene的索引文件格式(2)

    本文转载自:http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623599.html  略有删减和补充 四.具体格式 上面曾经交代过,L ...

  3. Lucene学习总结之三:Lucene的索引文件格式(1) 2014-06-25 14:15 1124人阅读 评论(0) 收藏

    Lucene的索引里面存了些什么,如何存放的,也即Lucene的索引文件格式,是读懂Lucene源代码的一把钥匙. 当我们真正进入到Lucene源代码之中的时候,我们会发现: Lucene的索引过程, ...

  4. Lucene系列-索引文件

    本文介绍下lucene生成的索引有哪些文件组成,每个文件包含了什么信息.基于Lucene 4.10.0. 数据结构 索引(index)包含了存储的文档(document)正排.倒排信息,用于文本搜索. ...

  5. Solr4.8.0源码分析(8)之Lucene的索引文件(1)

    Solr4.8.0源码分析(8)之Lucene的索引文件(1) 题记:最近有幸看到觉先大神的Lucene的博客,感觉自己之前学习的以及工作的太为肤浅,所以决定先跟随觉先大神的博客学习下Lucene的原 ...

  6. ES doc_values的来源,field data——就是doc->terms的正向索引啊,不过它是在查询阶段通过读取倒排索引loading segments放在内存而得到的?

    Support in the Wild: My Biggest Elasticsearch Problem at Scale Java Heap Pressure Elasticsearch has ...

  7. lucene正向索引(续)——每次commit会形成一个新的段,段"_1"的域和词向量信息可能存在"_0.fdt"和"_0.fdx”中

    DocStoreOffset DocStoreSegment DocStoreIsCompoundFile 对于域(Stored Field)和词向量(Term Vector)的存储可以有不同的方式, ...

  8. lucene正向索引(续)——一个文档的所有filed+value都在fdt文件中!!!

    4.1.3. 域(Field)的数据信息(.fdt,.fdx) 域数据文件(fdt): 真正保存存储域(stored field)信息的是fdt文件 在一个段(segment)中总共有segment ...

  9. lucene反向索引——倒排表无论是文档号及词频,还是位置信息,都是以跳跃表的结构存在的

    转自:http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661436.html 4.2. 反向信息 反向信息是索引文件的核心,也即反向索 ...

随机推荐

  1. Axios使用拦截器全局处理请求重试

    Axios拦截器 Axios提供了拦截器的接口,让我们能够全局处理请求和响应.Axios拦截器会在Promise的then和catch调用前拦截到. 请求拦截示例 axios.interceptors ...

  2. Java 之 字节流

    一.一切皆为字节 一切文件数据(文本.图片.视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此.所以,字节流可以传输任意文件数据.在操作流的时候,我们要时刻明确,无论使 ...

  3. iOS 内存管理的一点小问题

    现在大家的项目应该基本都是ARC了,如果还是MRC的话,赶紧转换到ARC吧!最近被临时拉过去开发iPad,由于项目原因,还是使用的MRC.今天在调部分界面的时候,发现一段代码,我怎么看都怎么觉得怪怪的 ...

  4. javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certificatio

    场景:Java调用PHP接口,代码部署在服务器上后,调用报错,显示PHP服务器那边证书我这边服务器不信任(我猜的). 异常信息: 2019-08-06 14:00:09,102 [http-nio-4 ...

  5. Computer Vision_33_SIFT:LIFT: Learned Invariant Feature Transform——2016

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  6. MySQL处理达到百万级数据时,如何优化?

    1.两种查询引擎查询速度(myIsam 引擎 ) InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行. ...

  7. 【DevOps】在CentOS中安装DockerCE

    准备 安装好CentOS7,拥有root账号密码,使用客户端登录. 安装 启动进入root用户,复制以下代码执行即可 yum install -y yum-utils device-mapper-pe ...

  8. Luogu P1062 数列

    Luogu P1062 数列 题目说: 把所有$k$的方幂及所有有限个互不相等的$k$的方幂之和构成一个递增的序列. 这就是说,每一个$k$的方幂只能有或没有. 有为$0$,没有为$1$. 所以这些数 ...

  9. HDU-1237- 简单计算器--栈的基本应用

    简单计算器 Problem Description 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值.   Input 测试输入包含若干测试用例,每个测试用例占一行,每行不 ...

  10. h5格式化微信 nickname 保留第一个字,其余用*显示

    截取微信nickname中需要注意的是,表情符号和特殊字符,如果你不用正则过滤掉的话,使用slice(0,1)直接截取第一个字符串是不行的,因为表情符号占用两个字节,截取一半,ios会报错,andro ...