探秘新一代向量存储格式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. 倒排索引:全文搜索

下一章讲向量索引。

相关推荐
悟空聊架构14 小时前
基于KaiwuDB在游乐场“刷卡+投币”双模消费系统中的落地实践
数据库·后端·架构
over69717 小时前
从 URL 输入到页面展示:一次完整的 Web 导航之旅
前端·面试·架构
Mintopia18 小时前
软件系统中的订单-审核业务架构分析与实践
后端·架构
三翼鸟数字化技术团队18 小时前
前端架构演进与模块化设计实践
前端·架构
天蓝色的鱼鱼1 天前
模块化与组件化:90%的前端开发者都没搞懂的本质区别
前端·架构·代码规范
乡村中医1 天前
AI Chat实现第二步,多会话流式输出的状态管理,教你如何实现多会话与历史内容懒加载
架构
文心快码BaiduComate2 天前
Comate 4.0新年全面焕新!底层重构、七大升级、复杂任务驾驭力跃升
前端·程序员·架构
DevnullCoffe2 天前
基于 OpenClaw + Pangolinfo API 的 Amazon 价格监控系统:架构设计与最佳实践
人工智能·架构
Mintopia2 天前
在深与广之间:产品、架构与开发如何为业务场景做权衡
架构