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

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

相关推荐
晚霞的不甘2 小时前
CANN 在工业质检中的亚像素级视觉检测系统设计
人工智能·计算机视觉·架构·开源·视觉检测
island13142 小时前
CANN HIXL 高性能单边通信库深度解析:PGAS 模型在异构显存上的地址映射与异步传输机制
人工智能·神经网络·架构
岁岁种桃花儿3 小时前
Flink CDC从入门到上天系列第一篇:Flink CDC简易应用
大数据·架构·flink
秋邱4 小时前
AIGC 的“隐形引擎”:深度拆解 CANN ops-math 通用数学库的架构与野心
架构·aigc
小a杰.4 小时前
CANN技术深度解析
架构
向哆哆4 小时前
CANN生态深度解析:ops-nn仓库的核心架构与技术实现
架构·cann
笔画人生4 小时前
系统级整合:`ops-transformer` 在 CANN 全栈架构中的角色与实践
深度学习·架构·transformer
程序猿追5 小时前
深度解码计算语言接口 (ACL):CANN 架构下的算力之门
架构
程序猿追5 小时前
深度解码AI之魂:CANN Compiler 核心架构与技术演进
人工智能·架构
艾莉丝努力练剑6 小时前
跨节点通信优化:使用hixl降低网络延迟的实战
架构·cann