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

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

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