【lucene】bitsetiterator

一句话:

`BitSetIterator` 就是把 java.util.BitSet 包装成 DocIdSetIterator 的“游标”,让你可以像扫普通倒排表一样,按 docID 从小到大遍历所有被置 1 的位,而不用自己手工 `nextSetBit(...)`。

---

1. 背景

Lucene 的 `DocIdSetIterator` 抽象只有两个核心动作:  

- `nextDoc()` – 返回下一个存在的 docID  

- `advance(target)` – 跳到 ≥ target 的第一个存在的 docID  

任何“文档号集合”想参与查询/过滤,都必须提供这个接口。

`BitSet` 本身只有 `get()/set()/nextSetBit(int)`,没有标准的迭代器语义,于是就有了 `BitSetIterator` 做适配。

---

2. 内部实现(8.5.0 代码)  

```java

final class BitSetIterator extends DocIdSetIterator {

  private final BitSet bits;

  private final int length; // 最大 docID + 1

  private int doc = -1; // 当前 docID

  BitSetIterator(BitSet bits, int length) {

    this.bits = bits;

    this.length = length;

  }

  @Override

  public int docID() { return doc; }

 

  @Override

  public int nextDoc() throws IOException {

    return advance(doc + 1);

  }

 

  @Override

  public int advance(int target) throws IOException {

    if (target >= length) {

      return doc = NO_MORE_DOCS;

    }

    return doc = bits.nextSetBit(target);

  }

 

  @Override

  public long cost() {

    return bits.cardinality(); // 估计还剩多少文档

  }

}

```

 

- 完全委托给 `BitSet.nextSetBit(...)`,O(1) 起步,最坏 O(n),但对稀疏集合仍很快。  

- `cost()` 直接返回 `cardinality()`,方便上层 `ConjunctionDISI/DisjunctionDISI` 做排序、选 lead。

---

3. 典型出场场景  

1. 缓存过滤器

   `CachingWrapperFilter` 把第一次计算出来的 `DocIdSet` 做成 `BitSet`,以后每次搜索直接 `BitSetIterator` 复现,避免重新倒排解压。  

2. 多值字段去重

   某些自定义 `FieldCache` 或 `DocValues` 去重逻辑,会先把出现过的 docID 记到 `BitSet`,再用 `BitSetIterator` 一次性吐出。  

3. 测试/调试

   单元测试里想快速构造一个“已知文档号集合”的 `Scorer`,直接 `new BitSetIterator(bitSet, maxDoc)` 即可。

---

4. 优劣速览

优点  

- 实现极简,无额外内存(除了 BitSet 本身)。  

- `advance` 是位级操作,对稀疏集非常高效。  

缺点  

- `BitSet` 用 `long[]` 存位图,对超大索引(>2B doc)会爆内存;Lucene 9 以后已逐步用 `RoaringDocIdSet` 替代。  

- 只能正向扫描,不支持倒序;如果业务需要 `previousDoc()` 得自己再包一层。  

---

一句话记忆

`BitSetIterator` = “把内存里的 0/1 位图变成 Lucene 能用的倒排游标”,专用于缓存、小集合、快速重建场景,是过滤器结果重用的最廉价方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值