探秘新一代向量存储格式Lance-format (十四) 索引系统架构

第14章:索引系统架构

🎯 核心概览

索引系统是 Lance 查询加速的核心。本章讲解索引接口设计、元数据管理和生命周期。


📊 第一部分:索引架构

Index Trait 定义

rust 复制代码
#[async_trait]
pub trait Index: Send + Sync + Serialize + Deserialize {
    /// 获取索引类型
    fn index_type(&self) -> IndexType;
    
    /// 构建索引
    async fn build(
        &mut self,
        source: DatasetRecordBatchStream,
        progress: impl Fn(BuildProgress) + Send,
    ) -> Result<()>;
    
    /// 搜索索引
    async fn search(
        &self,
        query: &SearchQuery,
    ) -> Result<SearchResult>;
    
    /// 索引大小(字节)
    fn size_bytes(&self) -> u64;
    
    /// 元数据
    fn metadata(&self) -> &IndexMetadata;
}

pub enum IndexType {
    BTree,
    Bitmap,
    Inverted,
    IvfFlat,
    IvfPq,
    Hnsw,
}

索引注册表

rust 复制代码
pub struct IndexRegistry {
    indices: HashMap<String, Arc<dyn Index>>,  // column_name → Index
}

impl IndexRegistry {
    pub fn register(&mut self, column: String, index: Arc<dyn Index>) {
        self.indices.insert(column, index);
    }
    
    pub fn get(&self, column: &str) -> Option<Arc<dyn Index>> {
        self.indices.get(column).cloned()
    }
    
    pub async fn search(
        &self,
        column: &str,
        query: &SearchQuery,
    ) -> Result<SearchResult> {
        let index = self.get(column)
            .ok_or(Error::IndexNotFound)?;
        index.search(query).await
    }
}

🔧 第二部分:索引元数据管理

IndexMetadata 结构

rust 复制代码
pub struct IndexMetadata {
    pub name: String,
    pub column: String,
    pub index_type: IndexType,
    pub created_at: i64,
    pub updated_at: i64,
    
    /// 构建参数(根据索引类型)
    pub parameters: HashMap<String, String>,
    
    /// 存储位置
    pub index_file: String,
    
    /// 大小(字节)
    pub size_bytes: u64,
    
    /// 覆盖的行范围
    pub min_row_id: u32,
    pub max_row_id: u32,
}

索引文件存储

python 复制代码
dataset/
└── indices/
    ├── embedding_ivf_pq.idx     # 向量索引
    │   ├── codebooks.bin        # PQ 码字本
    │   ├── ivf_list_0.bin       # 簇 0 的数据
    │   ├── ivf_list_1.bin       # 簇 1 的数据
    │   └── metadata.json        # 索引元数据
    │
    ├── price_btree.idx          # BTree 索引
    │   ├── nodes.bin            # BTree 节点
    │   └── metadata.json
    │
    └── category_bitmap.idx      # Bitmap 索引
        ├── bitmaps.bin          # 位图数据
        └── metadata.json

💫 第三部分:索引生命周期

索引构建

arduino 复制代码
Dataset.create_index("embedding", "ivf_pq")
    ↓
IndexBuilder::new()
    ↓
扫描源数据:
├─ 获取所有 embedding 列数据
├─ 约 1G 的向量数据
└─ 流式处理以节省内存
    ↓
训练:
├─ KMeans 聚类(学习质心)
├─ PQ 量化(学习码字本)
└─ 记录统计信息
    ↓
写入索引:
├─ 序列化码字本
├─ 序列化 IVF 列表
└─ 写入索引文件
    ↓
更新 Manifest:
├─ 添加 IndexMetadata
└─ 记录索引版本
    ↓
成功完成

索引更新

diff 复制代码
新 Fragment 添加后,索引如何更新?

场景:数据集已有 IVF_PQ 索引,现在追加新数据

选项 1:增量更新(推荐)
- 对新 Fragment 的向量进行 PQ 量化
- 使用现有的码字本(不重新训练)
- 快速完成

选项 2:全量重建
- 扫描所有数据(包括新 Fragment)
- 重新训练 KMeans 和 PQ
- 更新所有索引
- 更耗时但可能更准确

Lance 的策略:
- 数据量小(<10%)→ 增量
- 数据量大(>30%)→ 全量重建

索引删除

python 复制代码
dataset.drop_index("embedding")

# 内部:
# 1. 从 IndexRegistry 移除索引
# 2. 从 Manifest 移除 IndexMetadata
# 3. 异步删除索引文件
# 4. 更新 Dataset 元数据

# 成本:O(1) 元数据操作

📊 索引类型总览

索引类型 适用场景 成本 查询性能
BTree 范围查询 中等
Bitmap 精确匹配、低基数 极快
Inverted 全文搜索
IVF-FLAT 向量搜索(精确) 中等
IVF-PQ 向量搜索(大规模)
HNSW 向量搜索(动态)

📚 总结

索引系统架构:

  1. 统一接口:所有索引实现 Index trait
  2. 灵活注册:动态管理多个索引
  3. 自动元数据:完整的索引信息追踪
  4. 生命周期管理:创建、更新、删除
  5. 性能可观测:索引大小、覆盖范围等

下一章讲解标量索引的具体实现。

相关推荐
huipeng92621 分钟前
企业级微服务开发实战(一):项目启动与工程化设计
java·开发语言·spring boot·spring cloud·微服务·云原生·架构
沪漂阿龙4 小时前
Hermes Agent Sessions 架构详解:AI 如何跨平台延续任务、找回历史、持续推进工作
人工智能·架构
500844 小时前
昇腾 CANN 的五层架构,到底分了哪五层
java·人工智能·分布式·架构·ocr·wpf
贵慜_Derek5 小时前
《从零实现 Agent 系统》连载 07|记忆系统:短期上下文 vs 长期外部记忆
人工智能·设计模式·架构
05候补工程师5 小时前
从算法理想向工程现实的跨越:SLAM 核心架构、思维误区与 Nav2 实战避坑指南
人工智能·算法·安全·架构·机器人
dinl_vin5 小时前
FastAPI 系列·(三):依赖注入——用 Depends 构建分层架构
架构·fastapi
marsh02066 小时前
56 openclaw与Serverless:无服务器架构下的应用实践
云原生·架构·serverless
SmartBrain6 小时前
AI全栈开发(SDD):慢病管理系统工程级设计
java·大数据·开发语言·人工智能·架构·aigc
zandy10116 小时前
2026 BI平台与数据中台融合架构实践:从数据烟囱到统一智能数据层
大数据·架构·spark
rising start7 小时前
Web认证机制演进
架构·jwt·session