前言

Lucene全文检索主要分为索引、搜索两个过程,对于索引过程就是将文档磁盘存储然后按照指定格式构建索引文件,其中涉及数据存储一些压缩、数据结构设计还是很巧妙的,下面主要记录学习过程中的StoredField、DocValue以及磁盘BKD Tree的一些相关知识。

参考:

  • https://juejin.cn/post/6978437292549636132
  • https://juejin.cn/user/2559318800998141/posts
  • Lucene 原理与代码分析完整版.pdf
  • https://lucene.apache.org/core/9_9_0/core/org/apache/lucene/codecs/lucene99/package-summary.html#package.description
  • 美团外卖搜索基于 Elasticsearch 的优化实践

目录

  • Lucene数据分类
  • Lucene字段存储

1、Lucene数据分类

在Lucene中索引数据存储的逻辑层次有多个层次,从大到小依次是

  • index:索引代表了一类数据的完整存储
  • segment: 一个索引可能有一个或者多个段构成
  • doc: segment中存储的是一篇一篇的文档doc,每个segment是一个doc的集合
  • field: 每个doc都有多个field构成,filed才包含了具体的文本,类似于一个json对象的一个属性
  • term: 每个field的值可以进行分词,进而得到多个term,term是最基本的单元,每个field可以保存自己的词向量,用来计算搜索相似度

按照数据的维度整个Lucene把需要处理的数据分为这么几类

  1. PostingList,倒排表,也就是term->[doc1, doc3, doc5]这种倒排索引数据
  2. BlockTree, 从term和PostingList的映射关系,这种映射一般都用FST这种数据结构来表示,这种数据结构其实是一种树形结构,类似于Tire树,所以Lucene这里就叫BlockTree, 其实我更习惯叫它TermDict。
  3. StoredField一般类型的field原始数据存储
  4. DocValue 键值数据,这种数据主要用于数值、日期类型的field,是用来加速对字段的排序、筛选的,列式存储。
  5. TermVector词向量信息,主要记一个不同term的全局出现频率等信息,用于score,如搜索的str会被分为一个个term,然后会被转为指定维度的向量,存储文档维护索引会根据当前文档、所有文档中term出现的频率以得到一个当前term的权重创建一个对应的指定维度的向量,然后就计算查询相关性score。
  6. Norms用来存储Normalisation信息, 比如给某些field加权之类的。
  7. PointValue 用来加速 range Query的信息。

一个段索引维护的数据,Lucene9_9_0版本https://lucene.apache.org/core/9_9_0/core/org/apache/lucene/codecs/lucene99/package-summary.html#package.description

  • Segment info. This contains metadata about a segment, such as the number of documents, what files it uses, and information about how the segment is sorted。其中包含有关片段的元数据,例如文档数量、它使用的文件以及有关片段排序方式的信息
  • Field names. This contains metadata about the set of named fields used in the index.包含文档fields的元数据以及名称。
  • Stored Field values. This contains, for each document, a list of attribute-value pairs, where the attributes are field names. These are used to store auxiliary information about the document, such as its title, url, or an identifier to access a database. The set of stored fields are what is returned for each hit when searching. This is keyed by document number.以文档ID作为key,存储当前文档的fields键值对。
  • Term dictionary. A dictionary containing all of the terms used in all of the indexed fields of all of the documents. The dictionary also contains the number of documents which contain the term, and pointers to the term’s frequency and proximity data.包含所有文档的所有索引字段中使用的所有term的字典。该词典还包含包含该term的文档数量,以及指向该术语的频率和邻近数据的指针。
  • Term Frequency data. For each term in the dictionary, the numbers of all the documents that contain that term, and the frequency of the term in that document, unless frequencies are omitted (IndexOptions.DOCS)。term在当前文档出现的频率以及在全部文档出现的频率,主要用于score得分,比如term在当前文档出现的频率最高,在所有文档出现的频率最低,那么搜索该term在该文档中搜索得分高。
  • Term Proximity data. For each term in the dictionary, the positions that the term occurs in each document. Note that this will not exist if all fields in all documents omit position data。term出现在所有文档的位置,可省略。
  • Normalization factors. For each field in each document, a value is stored that is multiplied into the score for hits on that field.计算相关性score的时候可为某些field字段乘以一个系数。
  • Term Vectors. For each field in each document, the term vector (sometimes called document vector) may be stored. A term vector consists of term text and term frequency. To add Term Vectors to your index see the Field constructors。每一个文档的每一个field会有一个term向量,主要根据term出现的频率计算出来,用于搜索的score分值计算。
    • TextField: Reader or String indexed for full-text search。用于全文搜索。
    • StringField: String indexed verbatim as a single token
    • IntPoint: int indexed for exact/range queries.
    • LongPoint: long indexed for exact/range queries.
    • FloatPoint: float indexed for exact/range queries.
    • DoublePoint: double indexed for exact/range queries.
    • SortedDocValuesField: byte[] indexed column-wise for sorting/faceting,按列索引,用于排序
    • SortedSetDocValuesField: SortedSet indexed column-wise for sorting/faceting
    • NumericDocValuesField: long indexed column-wise for sorting/faceting
    • SortedNumericDocValuesField: SortedSet indexed column-wise for sorting/faceting
    • StoredField: Stored-only value for retrieving in summary results。仅存储值。
  • Per-document values. Like stored values, these are also keyed by document number, but are generally intended to be loaded into main memory for fast access. Whereas stored values are generally intended for summary results from searches, per-document values are useful for things like scoring factors.类似StoreField,可以更快加载到内存访问,用于搜索的摘要结果,但是每个文档的值对于评分因素有很大的影响。
  • Live documents. An optional file indicating which documents are live.一个可选文件,指定哪些文档是实时的。主要用于段数据删除时候,在段外部维护一个状态记录段的最新状态。
  • Point values. Optional pair of files, recording dimensionally indexed fields, to enable fast numeric range filtering and large numeric values like BigInteger and BigDecimal (1D) and geographic shape intersection (2D, 3D).可选的一对文件,记录维度索引字段,以启用快速数值范围过滤和大数值,例如 BigInteger 和 BigDecimal (1D) 以及地理形状交集(2D、3D)。
  • Vector values. The vector format stores numeric vectors in a format optimized for random access and computation, supporting high-dimensional nearest-neighbor search.

按照数据存储的方向维度可以分为

  • 一般存储形式:按层次保存了从索引,一直到词的包含关系:索引(Index) –> 段(segment) –> 文档 (Document) –> 域(Field) –> 词(Term) ,层次结构,则每个层次都保存了本层次的信息以及下一层次的元信息。如StoredFileld、DocValue存储形式。
  • 反向存储形式:如倒排索引(PostingList + BlockTree)数据存储形式。

2、Lucene存储文件

一个索引相关的存储文件对应一个文件夹,一个段的所有文件都具有相同的名称和不同的扩展名。扩展名对应于下面描述的不同文件格式。当使用复合文件格式时(小段的默认格式),这些文件(段信息文件、锁定文件和文件夹文档文件除外)将折叠为单个.cfs文件。

  • Segments info:多个段文件名永远不会重复使用。也就是说,当任何文件保存到目录时, 以前从未使用过的文件名。这是使用简单的生成方法实现的。比如说, 第一个段文件是segments_1,然后是segments_2,依此类推。生成是连续的长 以字母数字(以36为基数)形式表示的整数。主要保存段的元信息,segments_N 保存了此索引包含多少个段,每个段包含多少篇文档,实际的数据信息保存在field和词中的。
  • Write.lock:写锁默认存储在索引目录中,名为“write.lock”。如果锁目录与索引目录不同,则写锁将被命名为“XXXX-write.lock”,其中“”是从索引目录的完整路径导出的唯一前缀。如果存在此文件,则表示编写者正在修改索引(添加或删除文档)。这个锁文件确保一次只有一个writer修改索引。
  • Fields、Field Index 、Field Data:This is keyed by document number.也就是上面说的一般存储形式,保存了此段包含了多少个field,每个field的名称及索引方式以及数据
  • Term Vector Index、Term Vector Data:当你将字段设置为存储Term Vector时,Lucene会提取出该字段中每个词项的相关信息,并将其存储到倒排索引中。这样可以在搜索时不仅找到包含关键词的文档,还能得知每个关键词在文档中的频率和位置。因为不仅要根据倒排索引找到文档ID,还需要计算文档的相关性得分,会存储当前文档全部term的频率、位置信息,为了下一步也就是根据文档内全部的term的频率信息计算下面的vector value。
  • Vector values:根据每个文档的所有term vector data数据,为每个文档计算出一个指定的相关性vector values,然后在跟query vevtor计算相关性score。

3、Lucene数据存储

ps:学习分析Lucene版本为9_9_0

3.1、StoredField

In Lucene, fields may be stored, in which case their text is stored in the index literally, in a non-inverted manner. Fields that are inverted are called indexed. A field may be both stored and indexed.

保存字段属性信息的,过程主要关注各数据类型是如何存储的? 最终写入索引是如何压缩的?Lucene的field数据类型有下面几大类

  • int
  • long
  • Float
  • Double
  • String
  • bytes
3.1.1、int

// TODO

3.1.2、long
3.1.3、Float
3.1.4、Double
3.1.5、String
3.1.6、bytes

3.2、DocValue

用于倒排查找的数据,加速筛选和排序的,主要关注

  • DocValue 的类型有哪些?SortedNumericDocValue?SortedSet?应用场景等。
  • DocValue是如何存储的?