lucene系列(六)索引格式之fdt文件

前言

本文介紹一下.fdt 文件的存儲格式。java

fdt 文件,以正排的方式,存儲了 field 的原始真實數據。也就是說,你添加到全部中的全部 field 內容。都會存儲在此文件中。數組

.fdt 文件總體結構

2021-01-27-21-47-15

其中Header Footer, 與其中文件並沒有差異。詳細字段解釋能夠看 Lucene 系列(二)索引格式之 fdm 文件緩存

這裏主要看一下以 chunk 爲單位進行存儲的 field 信息。也就是圖中的這一部。微信

2021-01-28-14-06-51

其中。對於每個 chunk. 首先會存儲一個 ChunkHeader:markdown

2021-01-28-14-07-51

其中包括:ide

  • docBase : 當前 chunk 裏的第一個 docID.
  • numBufferedDocs << | slice . 當前塊裏面緩衝了多少個 doc, 能夠根據 docBase 及 num 來算出每個 docId. 還以 bit 的方式存儲了當前 chunk 是否分片。
  • 存儲每一個文檔有多少個 field. (數組)
  • 存儲每一個文檔的 field 信息長度(字節長度) (數組)

以後,會將當前 chunk 的全部 field 信息進行壓縮存儲。函數

2021-01-28-14-34-01

其中依次羅列了全部的 doc, 每一個 doc 中羅列了全部的 field.oop

field 信息中,存儲了:學習

  1. FieldNumberAndType: field 的編號及類型
  2. Value: 實際的值,根據不一樣類型 (int,long,string,bytes 等), 存儲方法不一樣。

寫入代碼分析

對。fdt 文件的寫入,主要是在CompressingStoredFieldsWriter類中進行。編碼

首先是在構造函數中寫入 IndexHeader.

2021-01-28-18-44-31

以後在每次調用flush(), 即每次緩存夠一個 Chunk 時,進行 field 信息的寫入。 2021-01-28-18-46-39

在圖中 1 處,寫入ChunkHeader.

2021-01-28-18-47-22

按序寫入了DocBase, numBufferedDocs|Sliced, NumStoredFields, lengths.

在圖中 2 處,將當前緩衝的全部 field 信息進行壓縮,寫入。

內存中緩衝的 field 信息中包含哪些內容呢?這部分的寫入在CompressingStoredFieldsWriter類的writeField()方法中。

/** * 寫了什麼? * 1.編號及類型 * 2. 內容 * 2.1 若是是基本類型,直接存儲 * 2.2 若是是 bytes, 寫長度和內容 * 2.3 若是是 string, 先寫長度,而後寫內容 */
  @Override
  public void writeField(FieldInfo info, IndexableField field) throws IOException {

    // 計數+1
    ++numStoredFieldsInDoc;

    int bits = 0;
    final BytesRef bytes;
    final String string;

    Number number = field.numericValue();
    if (number != null) {
      if (number instanceof Byte || number instanceof Short || number instanceof Integer) {
        bits = NUMERIC_INT;
      } else if (number instanceof Long) {
        bits = NUMERIC_LONG;
      } else if (number instanceof Float) {
        bits = NUMERIC_FLOAT;
      } else if (number instanceof Double) {
        bits = NUMERIC_DOUBLE;
      } else {
        throw new IllegalArgumentException("cannot store numeric type " + number.getClass());
      }
      string = null;
      bytes = null;
    } else {
      bytes = field.binaryValue();
      if (bytes != null) {
        bits = BYTE_ARR;
        string = null;
      } else {
        bits = STRING;
        string = field.stringValue();
        if (string == null) {
          throw new IllegalArgumentException("field " + field.name() + " is stored but does not have binaryValue, stringValue nor numericValue");
        }
      }
    }

    // 存儲了 field 的內部編號,以及當前 field 的類型,是四種數字呢,仍是字符串,仍是二進制串。
    // number , 一個 int, 右邊的 3 位是類型,左邊的是編號
    final long infoAndBits = (((long) info.number) << TYPE_BITS) | bits;
    bufferedDocs.writeVLong(infoAndBits);

    if (bytes != null) {
      bufferedDocs.writeVInt(bytes.length);
      bufferedDocs.writeBytes(bytes.bytes, bytes.offset, bytes.length);
    } else if (string != null) {
      bufferedDocs.writeString(string);
    } else {
      if (number instanceof Byte || number instanceof Short || number instanceof Integer) {
        bufferedDocs.writeZInt(number.intValue());
      } else if (number instanceof Long) {
        writeTLong(bufferedDocs, number.longValue());
      } else if (number instanceof Float) {
        writeZFloat(bufferedDocs, number.floatValue());
      } else if (number instanceof Double) {
        writeZDouble(bufferedDocs, number.doubleValue());
      } else {
        throw new AssertionError("Cannot get here");
      }
    }
  }

複製代碼

如代碼所示,首先分析了要存儲 field 的類型及編碼,以後將類型及編號寫入一個 long, 以及 field 的真實信息,根據不一樣的類型進行不一樣的編碼,以後緩衝到內存裏,等到一個 chunk 寫入完成或者最終調用 finish 時,批量的進行寫入。

結語

對 field 原始信息的寫入比較簡單。在每次添加一個 Document 時,循環調用添加 field. 將對應的 field 編號,類型,內容緩衝到內存裏,每次緩衝夠一個 Chunk, 進行壓縮寫入。


完。


以上皆爲我的所思所得,若有錯誤歡迎評論區指正。

歡迎轉載,煩請署名並保留原文連接。

聯繫郵箱:huyanshi2580@gmail.com

更多學習筆記見我的博客或關注微信公衆號 < 呼延十 >------>呼延十

相關文章
相關標籤/搜索