背景
在社区中看到有人提出一个问题,大意就是为什么启用压缩之后占用的空间大小为什么没变小。
原地址是ES索引默认的压缩功能有效果吗?
问题分析
其实这个问题就涉及到Lucene的文件结构了,Elasticsearch统计的存储空间中包括了很多内容,不止包括原文档,还有所有字段的索引,而Elasticsearch中对文档的压缩也仅限于_source
这个存储了原JSON格式的字段(实际上应该是fdt这个文件的压缩方式,默认是LZ4),因此可能会出现这个朋友发现的这种情况。今天有时间我就来整理一下Lucene的文件结构。
另外,提问中的空间大小还涉及到了segment
的多少,一般来说,刚完成数据索引的索引,如果segment
比较多也可能会占用更大的空间。
Lucene文件
基本概念
Lucene 有几个关键词,index
,document
,field
和term`。
index
包括 很多document
,就像是一张表有很多行记录。
document
包括很多field
,就像一条记录的不同字段。
term
这个概念就不能简单的用关系型数据库来理解了,但是也可以想象成,字段中的数据,但是这个字段的数据是数组形式,一个term
就是数组中的一个值。
倒排索引
Lucene中用于存储索引的结构叫倒排索引Inverted Indexing
,倒排索引时以term
为单位的,对于文本字段来说,每个字段都会有一个倒排索引。
字段类型
在Lucene中的字段类型一共只有三种,文本,数值,二进制。
segment 段
一个索引有一个或者多个段组成,这样设计的原因是为了更方便的进行更新或者修改数据,而不会对旧的索引更新,防止大量更新的情况下影响搜索性能。
每当有新的文档进入,会按照批次创建新的段,然后持久化到磁盘中。
段只存在于磁盘。
文件编号
在内部,Lucene通过整数文档编号引用文档。添加到索引的第一个文档编号为零,并且添加的每个后续文档都比前一个更大。
请注意,文档的编号可能会更改,因此在将这些编号存储在Lucene之外时应小心。特别是,在以下情况下,数字可能会发生变化:
1. 存储在每个段中的数字仅在段内是唯一的,并且必须先进行转换才能在更大的上下文中使用。标准技术是根据该段中使用的数字范围为每个段分配一系列值。要将文档编号从段转换为外部值,请添加段的基本文档编号。要将外部值转换回特定于段的值,将通过外部值所在的范围来标识该段,并减去该段的基值。例如,可以组合两个五个文档段,使得第一个段的基值为零,五个中的第二个段。来自第二段的文档3的外部值为8。
2. 删除文档时,会在编号中创建间隙。随着索引通过合并演变,这些最终会被删除。合并段时删除已删除的文档。因此,新合并的细分市场的编号没有差距。
索引结构
每个段索引都保持以下内容:
-
Segment info
。这包含有关段的元数据,例如文档数,它使用的文件, -
Field names
。它包含索引中使用的字段名称集。 -
Stored Field values
。对于每个文档,这包含属性 - 值对的列表,其中属性是字段名称。这些用于存储有关文档的辅助信息,例如其标题,URL或访问数据库的标识符。存储的字段集是搜索时为每个匹配返回的字段。这是由文件编号键入的。 -
Term dictionary
。包含所有文档的所有索引字段中使用的所有术语的字典。字典还包含包含该术语的文档数量,以及指向术语频率和接近度数据的指针。 -
Term Frequency data
。对于字典中的每个术语,包含该术语的所有文档的编号以及该文档中术语的频率,除非省略频率(IndexOptions.DOCS_ONLY) -
Term Proximity data
。对于词典中的每个术语,术语在每个文档中出现的位置。请注意,如果所有文档中的所有字段都省略位置数据,则不存在此操作。 -
Normalization factors
。对于每个文档中的每个字段,存储一个值,该值乘以该字段上的匹配分数。 -
Term Vectors
。对于每个文档中的每个字段,可以存储术语向量(有时称为文档向量)。术语向量由术语文本和术语频率组成。要将术语向量添加到索引,请参阅Field
构造函数 -
Per-document values
。DocValues ,用于排序,聚合 -
Live documents
。一个可选文件,指示哪些文档是活动的。 -
Point values
。可选的文件对,记录尺寸索引字段,以实现快速数值范围过滤和大数值,如BigInteger和BigDecimal(1D)以及地理形状交叉(2D,3D)。
有关这些内容的详细信息,请参见其链接页面。
文件命名
属于段的所有文件具有相同的名称和不同的扩展名。扩展名对应于下面描述的不同文件格式。使用复合文件格式(小段默认)时,这些文件(段信息文件,锁定文件和已删除文档文件除外)将折叠为单个.cfs文件(有关详细信息,请参阅下文)
通常,索引中的所有段都存储在单个目录中,但这不是必需的。
永远不会重复使用文件名。也就是说,当任何文件保存到目录时,它将被赋予一个前所未有的文件名。这是使用简单的世代方法实现的。例如,第一段文件是segments_1,然后是segments_2等。生成是以字母数字(基础36)形式表示的顺序长整数。
文件扩展名记录
lock锁
write.lock是存储于索引目录中,用来标识目前有进程在操作这个索引,防止多个writer同时写入产生错误。