Lucene 8.5.0 的 `.pos` 文件**逻辑结构**

Lucene 8.5.0 的 `.pos` 文件**逻辑结构**(按真实实现重新整理)

```

.pos 文件

├─ Header (CodecHeader)

├─ TermPositions × TermCount ← 每个 term 一段,顺序由词典隐式决定

│ ├─ PackedPosDeltaBlock × N ← 仅当 **无 payload 且 无 offset** 时存在

│ │ └─ 64 个 position-delta(PackedInts 压缩)

│ ├─ VIntBlock × PosVIntCount ← 必写;剩余所有位置

│ │ ├─ PositionDelta VInt

│ │ ├─ PayloadLength? VInt ← 最低位标记法,payload 启用时出现

│ │ ├─ PayloadData? byte[len] ← **尾巴**阶段内联;整块阶段在 .pay

│ │ ├─ OffsetDelta? VInt ← offsets 启用时出现

│ │ └─ OffsetLength? VInt ← 同上

└─ Footer (CodecFooter)

```

关键结论

`TermPositions` 就是一段连续的二进制数据,其内部按顺序包含:

  • 0 个或多个 `PackedPosDeltaBlock`(≥64 个 delta 时才有)

  • 1 个 `VIntBlock`(剩余尾巴,长度 ≥0)

因此:

TermPositions = [PackedPosDeltaBlock × N] + VIntBlock

  1. **PackedPosDeltaBlock** 只存 **纯 position delta**;

  2. **只要启用 payload 或 offset,则 PackedPosDeltaBlock 不出现**,全部走 VIntBlock;

  3. **payload bytes** 在"尾巴"阶段 **内联在 `.pos`**,整块阶段 **在 `.pay`**;

  4. **offset 元数据** 始终写在 `.pos` 的 VIntBlock。