探秘新一代向量存储格式Lance-format (十五) 标量索引实现

第15章:标量索引实现

🎯 核心概览

BTree、Bitmap 和倒排索引是标量数据加速的三大支柱。


📊 BTree 索引

原理

BTree 是自平衡的排序树,支持范围查询。

css 复制代码
         [50]
        /    \
      [25]   [75]
     /   \   /   \
   [10] [30][60] [90]

实现

rust 复制代码
pub struct BTreeIndex {
    root: BTreeNode,
    comparator: Box<dyn Fn(&[u8], &[u8]) -> Ordering + Send + Sync>,
}

impl BTreeIndex {
    pub fn range_search(&self, min: &[u8], max: &[u8]) -> Vec<u32> {
        // 返回 [min, max] 范围内的行号
        let mut result = Vec::new();
        self.traverse_range(&self.root, min, max, &mut result);
        result
    }
}

查询性能

diff 复制代码
100万行,price 列有 BTree 索引

查询:WHERE price BETWEEN 100 AND 500

无索引:
- 扫描 100万行
- 时间:10ms

BTree 索引:
- 查找最小值:log(1M) ≈ 20 次比较
- 范围扫描:500 行
- 时间:0.5ms
- 加速:20 倍

🎯 Bitmap 索引

原理

对每个不同的值存储一个位图。

less 复制代码
category 列:[A, B, A, C, B, A]

位图表示:
A: [1, 0, 1, 0, 0, 1]
B: [0, 1, 0, 0, 1, 0]
C: [0, 0, 0, 1, 0, 0]

查询 category = 'A' → 直接返回位图 [1, 0, 1, 0, 0, 1]

实现

rust 复制代码
pub struct BitmapIndex {
    bitmaps: HashMap<ScalarValue, RoaringBitmap>,
}

impl BitmapIndex {
    pub fn search(&self, value: &ScalarValue) -> Option<RoaringBitmap> {
        self.bitmaps.get(value).cloned()
    }
    
    pub fn search_multiple(
        &self, 
        values: &[ScalarValue],
        operator: Operator,  // AND, OR, NOT
    ) -> RoaringBitmap {
        // 支持复杂的位操作
        // WHERE category IN ('A', 'B')
        // 返回:bitmap_A OR bitmap_B
    }
}

性能

diff 复制代码
100万行,category 列(100 种不同值)

无索引:
- 扫描 100万行
- 时间:10ms

Bitmap 索引:
- 位图查找:O(1)
- 位操作:O(行数/64)
- 时间:1ms
- 加速:10 倍

📚 倒排索引(全文搜索)

原理

为每个单词存储出现位置。

less 复制代码
文档:["hello world", "world of tanks", "hello there"]

倒排表:
hello: [doc_0, doc_2]
world: [doc_0, doc_1]
of: [doc_1]
tanks: [doc_1]
there: [doc_2]

查询 "hello world" → 
(doc_0, doc_2) ∩ (doc_0, doc_1) = doc_0

Lance 中的实现

rust 复制代码
pub struct InvertedIndex {
    // 使用 Tantivy 库实现全文索引
    index: tantivy::Index,
}

impl InvertedIndex {
    pub fn search(&self, query: &str) -> Result<Vec<u32>> {
        let searcher = self.index.reader()?.searcher();
        let query_parser = QueryParser::for_index(&self.index, vec![...]);
        let query = query_parser.parse_query(query)?;
        
        let top_docs = searcher.search(&query, &TopDocs::with_limit(1000))?;
        Ok(top_docs.iter().map(|(score, addr)| {
            // 转换为行号
        }).collect())
    }
}

💡 何时使用哪种索引

scss 复制代码
数据类型 | 查询类型 | 推荐索引
---------|--------|--------
整数    | 范围    | BTree
整数    | 精确    | Bitmap (如果不同值<1000)
字符串   | 精确    | Bitmap (如果不同值<1000)
字符串   | 前缀    | Trie/Prefix Tree
文本     | 全文    | Inverted Index
向量     | 相似    | IVF/HNSW

📊 总结

标量索引提供了针对不同查询模式的优化:

  1. BTree:范围查询
  2. Bitmap:精确匹配和低基数列
  3. 倒排索引:全文搜索

下一章讲向量索引。

相关推荐
5***b972 小时前
什么是射频?射频基本架构?
架构
settingsun12253 小时前
分布式系统架构:百万并发系统设计
云原生·架构·分布式系统
谷隐凡二3 小时前
Kubernetes主从架构简单解析:基于Python的模拟实现
python·架构·kubernetes
c***69303 小时前
超详细:数据库的基本架构
数据库·架构
Mintopia4 小时前
无界微前端:父子应用通信、路由与状态管理最佳实践
架构·前端框架·全栈
L***86535 小时前
【架构解析】深入浅析DeepSeek-V3的技术架构
架构
Peter_Monster5 小时前
大语言模型(LLM)架构核心解析(干货篇)
人工智能·语言模型·架构
拾忆,想起6 小时前
Dubbo分组(Group)使用指南:实现服务接口的多版本管理与环境隔离
分布式·微服务·性能优化·架构·dubbo
todoitbo6 小时前
基于MCP架构的DevUI多组件协作实践:打造智能业务分析平台
华为·ai·架构·devui·matechat