探秘新一代向量存储格式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. 性能可观测:索引大小、覆盖范围等

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

相关推荐
DBA_G2 小时前
南大通用GBase 8s数据库新存储引擎核心能力二
数据库·微服务·架构
何时梦醒6 小时前
React + TypeScript + Vite 实战:从零构建 Color Picker 应用
前端·javascript·架构
张忠琳8 小时前
【NVIDIA】k8s-device-plugin v0.19.3 标签管理模块 (internal/lm) 深度分析之六
云原生·容器·架构·kubernetes·nvidia
中微极客9 小时前
边缘AI赋能可穿戴:实时生物信号处理架构与工程实践
人工智能·架构·信号处理
qq_4542450310 小时前
认知自举:LLM自我指令泛化的三层逻辑
人工智能·架构·prompt
XUHUOJUN10 小时前
Azure Stack Hub 存储服务:托管磁盘、Blob/Table/Queue 与容量管理(下篇)
架构·azure stack
shaodong112310 小时前
HarmonyOS 多设备开发实践:我把 SysCap、断点和折叠屏适配放到了同一套架构里
华为·架构·harmonyos·鸿蒙
XUHUOJUN11 小时前
Azure Stack Hub 存储服务:从 S2D 物理栈到租户服务全景(上篇)
架构·azure stack
上海云盾商务经理杨杨11 小时前
WAF+DDoS 双层防护架构!解决应用层混合攻击漏杀误杀问题
架构·ddos
马优晨12 小时前
pring Boot + MyBatis + Redis 项目分层架构详解 —— 各层职责、关系与工作流程
架构·mybatis·spring项目分层架构详解·spring项目架构详解·spring各层职责·spring关系与工作流程