資料來源:
- 官方 Java Docs
- 源碼目錄:lucene-9.4.1-src/lucene-9.4.1/lucene/core/src/java/org/apache/lucene/codecs/lucene94/package-info.java
Package org.apache.lucene.codecs.lucene94
Lucene 9.3 file format.
Apache Lucene - Index File Formats
介紹
定義
倒排索引
field 類型
段
doc id
索引結(jié)構(gòu)概述
File Naming
Summary of File Extensions
Lock File
History
Limitations
介紹
此文檔定義了當(dāng)前 Lucene 版本的索引文件格式。If you are using a different version of Lucene, please consult the copy of docs/ that was distributed with the version you are using.
本文試圖提供 Apache Lucene 文件格式的高級定義。
定義
Lucene 的基本概念是索引(index)、文檔(document)、字段(field)和詞(term):
- 一個 index 是由多個 doc 組成的
- 一個 doc 是由多個 field 組成的
- 一個 field 是由多個 term 組成的
- 一個 term 是由多個 byte 組成的
文檔 Document
doc 是 json 格式的文本,一個簡單的例子:
{"k0":"123", "k1":"123", "k2":"hello world"}
域 Field
field 是一個 json 的 element,由 field name 和 field value 組成,field value 通常叫做 filed text。
上面 doc 例子中共有 3 個 field:
- field0:
"k0":"123",field name 為 k0,field text 為 123 - field1:
"k1":"123",field name 為 k1,field text 為 123 - field2:
"k2":"hello world",field name 為 k2,field text 為 hello world
詞 Term
源代碼:lucene-9.4.1-src/lucene-9.4.1/lucene/core/src/java/org/apache/lucene/index/Term.java
MySQL 的基本檢索單位是 column,由 column name 和 column value 組成;類似的,在 Lucene 基本檢索單位是 term,term 由 term name 和 term value 組成:
- term name 等同于 field name,數(shù)據(jù)格式為
text。 - term value 是 field text 的子集,我們通過分詞的方式,例如 split() 方法,將 field text 劃分為多個 term value,數(shù)據(jù)格式為
string。
分詞 tokenize 在 Lucene 中是一個很基本操作,在創(chuàng)建倒排索引時會用到,在進行檢索時也會用到。不同的語言、不同的分詞方式,會導(dǎo)致很多分詞器 tokenizer 的產(chǎn)生,這些分詞器通常以插件的形式(jar 包)存在
假如使用空格作為分隔符來進行分詞,那么上面的 doc 例子中共有 4 個 term:
- term0:
"k0":"123",term name 為 k0,term value 為 123 - term1:
"k1":123,term name 為 k1,term value 為 123 - term2:
"k2":"hello",term name 為 k2,term value 為 hello - term3:
"k2":"world",term name 為 k2,term value 為 world
term0 和 term1 雖然 value 的內(nèi)容是一樣的,但 ,term name 不一樣,所以 term0 和 term1 會被當(dāng)做 2 個不同的 term。
倒排索引
Lucene 的 index 存儲了 term 和 term 的統(tǒng)計信息,使得基于 term 的搜索更加高效。
類似于 MySQL 的 column 索引,Lucene 的 term 也有索引,它們都是針對 value 建立索引,但是不同的是 column 索引是正排索引, 而 term 索引是一個倒排索引(inverted index)。在正常思維中,我們通常先找到 doc,再找到 doc 里面的 term,這就是正排索引建立的基本邏輯;而倒排索引的基本邏輯是,通過指定的 term,反過來找包含這個 term 的 doc 。
Types of Fields
一個 field 既可以被存儲,也可以被索引:
- 被存儲的意思就是:把 field 的原數(shù)據(jù)以非倒排的方式存儲在 index 中
- 被索引的意思就是:開啟了索引特性的 field,則把 field 信息加入到倒排索引中
也就是說,一個 Lucene index,不但存儲了 field 原數(shù)據(jù),也存儲了 field 的索引,這 2 種數(shù)據(jù)存儲在不同的文件中,文件格式也不一樣。
建立倒排索引時,按照用戶定義的分詞方式,field text 既可能被分割成多個 term,也可能被當(dāng)成 1 個 term,例如進行自然語言識別時,后者效果顯然比前者的要好。
段
Lucene index 由多個子索引組成,子索引又稱作段 segment 。每一個 segment 都是一個完全獨立的 index,提供獨立的讀寫功能。所以 index 與 segment 之間有以下表現(xiàn):
- 新加的 doc 有可能寫入現(xiàn)有的 segment,也有可能寫入一個新創(chuàng)建的 segment
- 多個 segment 之間會發(fā)生合并 merge
- 1 個檢索可能會涉及到多個 segment
文檔編號
在 Lucene 內(nèi)部,使用文檔編號 document number 來表示一個文檔, document number 也叫 document id。index 的第一個 doc 編號為 0,依次遞增。
請注意,文檔編號可能會變化,因此在 Lucene 之外存儲這些數(shù)字時要小心。一般來說,一下幾種情況會導(dǎo)致文檔編號發(fā)生變化:
-
存儲在每個 segment 中的文檔編號僅在該 segment 內(nèi)是唯一的,必須進行轉(zhuǎn)換才能在更大的上下文中使用。標(biāo)準(zhǔn)的技術(shù)是根據(jù) segment 中使用的數(shù)字范圍為每個 segment 分配一個值范圍。要將文檔編號從 segment 內(nèi)部值轉(zhuǎn)換為外部值,需要添加 segment 的基本文檔編號。要將外部值轉(zhuǎn)換回特定 segment 的值,需要根據(jù)外部值所在的范圍識別出該 segment,并減去該 segment 的基本文檔編號。例如,要組合兩個只有 5 個文檔的 segment 時,第一個 segment 的基本文檔編號 0,第二個 segment 的基本文檔編號為 5,那么可以推斷出第二部分中的 doc3 的外部值為 8 = 5+3:
文檔 基本文檔編號 原段內(nèi)文檔編號 合并后的段外文檔編號 segment0 0 0-4 doc3 的為 3 = 0+3 segment1 5 0-4 doc3 的為 8 = 5+3 刪除文檔時,相關(guān)的文檔編號不再指向任何文檔,因此會產(chǎn)生空白編號。當(dāng)合并 segment 時,會生成一個新的 segment,已刪除的文檔會被丟棄,文檔編號也會重新生產(chǎn)。因此,新合并的段沒有空白編號。
索引結(jié)構(gòu)概述
每個 segment index 包含以下信息:
- Segment info:segment 元數(shù)據(jù),例如 segment 的 doc 數(shù)量、segment 使用的文件、segment 存儲的方式等
- Field names:field name 元數(shù)據(jù)
- Stored Field values:field 原始數(shù)據(jù),在 Lucene 中在存儲 doc 時不是直接整個 doc 進行存儲的,而是將其拆成多個 attribute-value 對,再進行列式存儲,attribute 是 field name,value 是 field text。 當(dāng)檢索命中時,返回 field 原始數(shù)據(jù),key 是文檔編碼。
- Term dictionary:term 詞典,當(dāng) field 開啟索引功能時,把 term 記錄到這個詞典中,該詞典還記錄了包含 term 的文檔數(shù)量、指向 term 詞頻和位置數(shù)據(jù)的指針。
- Term Frequency data:term 詞頻數(shù)據(jù),在 term 詞典中,如果沒有設(shè)置忽略 term 詞頻,那么每個 term 都有一個 term 出現(xiàn)次數(shù)的匯總,稱之為詞頻。
- Term Proximity data:term 位置數(shù)據(jù),在 term 詞典中,如果沒有設(shè)置忽略 term 位置數(shù)據(jù),那么每個 term 都會記錄它的每一個原文檔編碼 ,稱之為位置數(shù)據(jù)。
- Normalization factors:歸一化因子,在 doc 的每個 field 中,都存儲著一個值,用來乘以命中分?jǐn)?shù),實現(xiàn)歸一化的效果,使得搜索得分不因 doc 長度不同而出現(xiàn)較大偏差。For each field in each document, a value is stored that is multiplied into the score for hits on that field.
- Term Vectors:term 向量由 term text 和 term 詞頻組成,doc 的每個 field 可以選擇是否存儲 term 向量(有時也叫 doc 向量),請參考 Field 結(jié)構(gòu)
- Per-document values. 與存儲值一樣,這些值也以文檔編號為鍵,但通常是為了快速訪問而加載到主內(nèi)存中。存儲值通常用于搜索的摘要結(jié)果,而每個文檔的值對于諸如評分因子之類的東西很有用。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.
- 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).
- Vector values. The vector format stores numeric vectors in a format optimized for random access and computation, supporting high-dimensional nearest-neighbor search.