文章目录
总览
首先说明,这一篇文章有点过时了,可以参考这篇更加全面来看
这里主要想要介绍一下lucene的存储层面的东西,lucene的设计本来就很精巧,所以想了解需要花一些心思的。
- lucene的数据类型
- lucene包含了哪些信息
- 拥有哪些文件
1. lucene的数据类型
Byte:是最基本的类型,长8位(bit)。
Int32:由4个Byte组成。
Long64:由8个Byte组成。
VInt:可变字节的int,更小的数字比int32使用了更小的字节数
VLong: 可变字节的long类型
ZInt: 这个用来表示比较小的有符号数,也就是负数
ZLong: 同ZInt
VInt详解
- vint可能包含1-5 byte,对于每个byte的8位,其中后7位表示数值,最高1位表示是否还有另一个Byte,0表示没有,1表示有。这样的话小的int数字使用的字节数就更小。
- 前面的Byte表示数值的低位,越后面的Byte表示数值的高位。
比如 127 如果使用int表示,是0x00 0x00 0x00 01111111
但是使用vint 就是01111111
128 使用int 表示 是0x00 0x00 0x00 10000000
但是使用vint 就是10000000 00000001
第一个字节表示低7位,是0 ,但是因为后面还有一个字节,所以最高位是1,第二个字节表示的是第8-14位,所以是1,而且没有更多的字节了,所以最高位为0
可以看到,VInt在表示小整数的时候很有优势,但是在表示小的负整数的时候就没有优势了,反而会耗费比较大的字节数,因此又使用了zig-zag压缩方式来压缩负数
ZInt 详解
核心思想是用无符号数来表示有符号数字,正数和负数交错,使用 zigzag 编码,绝对值小的数字,无论正负都可以采用较少的 byte 来表示,充分利用了 Varint 这种技术。
一般的使用过程是,先使用zigzag编码算法对数字进行编码(不论是负数还是正数),然后得到的都是正数,这个时候再使用VInt进行压缩。
具体的转换相对麻烦一些,这里贴一个连接
2. lucene的基本结构
这里主要从两个方面来介绍lucene的数据结构,一方面是从逻辑上看看lucene的数据结构都有哪些,另一方面,看看从物理文件上看这些数据都是如何被保存的。
从逻辑上来讲,lucene实例就是一个索引,主要由段构成,每个索引可以有多个段组成,其物理存储关注的也就是这几个段是如何存储的。
1. doc number
在内部,Lucene通过整型(integer)文档(document number)编号引用文档(index)。添加到索引(index)中的首个文档(document)编号为0,后续添加的文档(document)其编号依次增长1。
- 文档(document)的编号可能会改变,因此在Lucene外部存储文档编号(document number)时应谨慎。
- 每段(segment)中存储的编号仅在本段(segment)内唯一,在更大的上下文(context)中使用前必须进行转换。标准是依据每段(segment)使用的数值范围为其分配一个范围的值。要将文档编号(document number)从段(segment)内转换为一个外部值,需要给(这个编号)添加段(segment)内基本文档编号(document number)。要将外部值转换为特定段(segment-specific)的值,此段(segment)需检查外部值是否在数值范围内,并(使外部值)减去段(segment)的基本文档编号。例如,两个五篇文档(document)的段(segment)将要合并(merge),那么第一个段(segment)的基本值为0,第二个的基本值为5(之前的文档里值的总数,第一段合并前文档中总数为0,第二段合并前,第一段已合并完,文档总数为5)。第二段(segment)的3号文档(document)的外部值将为8(3+5)。
- 当文档被删除(delete),编号中会产生间隔。随着索引(index)的通过合并(merge)的演变,这些(间隔)最终会被移除(remove)。被删除的文档在段(segment)合并(merge)时会被物理删除(drop)。新合并(merge)的段(segment)编号中就没有间隔了。
2. 段(segment) 的信息
- Segment info:包含了一个segment的元信息,比如documents的数量,是否使用了复合文件等信息
- Field names:包含了索引中所有的filed的信息
- Stored Field values: 存储每个doc的filed信息,是一个Map<k,v>的结构,k是域名,v是域的值,按照doc number进行分组
- Term dictionary: term词典,包含了所有文档的全部的分词后的词(也有可能是keyword)。同时还包含了该term所在文档数量,以及指向词频信息和位置信息的指针。
- Term Frequency data: 词频信息,包含该词汇的文档的数量df,以及 在每篇文档中出现的频次tf
- Term Proximity data: 词位置信息,词存储在每篇文档中出现的位置。
- Normalization factors: 标准化因子,对文档中的每一个域存储一个值(不是每个term),这个值在计算打分的时候会乘以计算出来的分数
- Term Vectors: 词向量,对于文档中的每个域(field),可以存储词向量,有时称作文档向量(document vector))。词向量(term vector)由词(term)的文本和词频(term frequency)组成
- Per-document values:类似stored values ,也是用doc number 来进行分组,但其通常加载到主内存中以便快速访问。经常用来存储一些搜索的总结性结果,单个文档值对于打分元素(scoring factors)这类过程非常有用。
- Live documents:一个辅助行的用来标识哪些文档是活跃状态的文件。
- Point values:一个可选的文件,用来记录多维度的数据类型,同时也支持通过大数字的范围过滤,比如bigInteger ,地理位置信息等
3. 文件信息
每一个段都包含了很多个文件来存储不同的信息。存储不同信息的文件的拓展名不一样,但是对于同一个段来说,所有的归属该段的文件名都是一致的。
如果使用复合的文件格式的话,会把多个段的数据信息存在一个文件当中(一般都是多个小段,当然 除了段的元数据文件,lock文件,和del文件),这个复合文件是.cfs文件。
通常情况下,一个索引下的所有段(segment)存储在单个目录(dierctory)中,尽管这不是必须的。
文件名不会重复使用,这个使用了按代增长的方式,,比如segment_1, segment_2等,每一代是一个有序的长整型数字,进行base36编码(5位一个新字节)的方式展现出来。
Name | Extension | Brief | Description |
---|---|---|---|
Segments File | segments_N | Stores information about a commit point | |
Lock File | write.lock | The Write lock prevents multiple IndexWriters from writing to the same file. | |
Segment Info | .si | Stores metadata about a segment | |
Compound File | .cfs, .cfe | An optional “virtual” file consisting of all the other index files for systems that frequently run out of file handles. | |
Fields | .fnm | Stores information about the fields | |
Field Index | .fdx | Contains pointers to field data | |
Field Data | .fdt | The stored fields for documents | |
Term Dictionary | .tim | The term dictionary, stores term info | |
Term Index | .tip | The index into the Term Dictionary | |
Frequencies | .doc | Contains the list of docs which contain each term along with frequency | |
Positions | .pos | Stores position information about where a term occurs in the index | |
Payloads | .pay | Stores additional per-position metadata information such as character offsets and user payloads | |
Norms | .nvd, .nvm | Encodes length and boost factors for docs and fields | |
Per-Document Values | .dvd, .dvm | Encodes additional scoring factors or other per-document information. | |
Term Vector Index | .tvx | Stores offset into the document data file | |
Term Vector Data | .tvd | Contains term vector data. | |
Live Documents | .liv | Info about what documents are live | |
Point values | .dii, .dim | Holds indexed points, if any |
3. 文件详细信息
1.segment_N
segment_N文件中记录了当前索引有哪些活跃的段(segment)。在一个index的目录下有可能有一个或者多个segment_N文件,但是只有N值最大的那个文件是有效文件(旧的segment_N存在一般是因为这些文件暂时还不能被删掉,或者是使用了自定义的IndexDeletionPolicy 策略)。segment_N包含每个段的name以及这个段使用的编码(codec)和对应的删除文件。
内容格式:
segments_N: Header, LuceneVersion, Version, NameCounter, SegCount, MinSegmentLuceneVersion, <SegName, SegID, SegCodec, DelGen, DeletionCount, FieldInfosGen, DocValuesGen, UpdatesFiles>SegCount, CommitUserData, Footer
解释:
Header: 一个uint32的魔数,当前文件编码,一个字符串标识文件格式,一个version 数字(标识当前文件的version目前不太明确),一个16byte的id,一个字节标识后缀长度,对应多个字节标识后缀内容
LuceneVersion: 这次lucene commit (每次提交会产生一个segment_N),使用的lucene的version,使用了三个vint,标识主版本,小版本,bugfix版本(这个和lucene的version记录方式密切相关)
Version: 这个记录了当前index被add和deleting操作改变的次数
NameCounter: 用来生成新的segment file的文件名,也就是代
SegCount:包含的segment的数量
MinSegmentLuceneVersion:最老的segment使用的lucene 对应的 version
未完待续