探秘新一代向量存储格式Lance-format (二) 项目结构与模块划分

第2章:项目结构与模块划分

概述

Lance 作为一个完整的列式数据格式系统,采用了精心设计的模块化架构。其核心实现使用 Rust 编写,并通过 PyO3 为 Python 提供高性能绑定。本章将深入解析 Lance 的模块划分设计、模块间依赖关系,以及各模块的核心职责。

架构设计总览

分层架构

Lance 项目采用了清晰的分层架构,从下往上分为以下层次:

scss 复制代码
┌─────────────────────────────────────────┐
│  应用层 (Python API/Java API/Rust API)  │
├─────────────────────────────────────────┤
│  查询引擎层 (DataFusion 集成)            │
├─────────────────────────────────────────┤
│  数据集层 (Dataset/Transaction/Fragment) │
├─────────────────────────────────────────┤
│  索引层 (Vector/Scalar Index)            │
├─────────────────────────────────────────┤
│  表管理层 (Manifest/Commit/RowID)        │
├─────────────────────────────────────────┤
│  存储层 (File Format/Encoding/IO)        │
├─────────────────────────────────────────┤
│  核心层 (Core Data Types/Cache)          │
├─────────────────────────────────────────┤
│  对象存储 (S3/Azure/GCS/Local)           │
└─────────────────────────────────────────┘

Rust 核心模块详解

1. lance-core - 核心类型系统

职责

  • 定义基础数据类型(Arrow 类型扩展)
  • 容器抽象(Container trait)
  • 缓存接口定义
  • 错误处理与工具函数

核心文件

rust 复制代码
src/
├── cache.rs          # 缓存接口定义
├── container.rs      # 数据容器抽象
├── datatypes.rs      # Lance 数据类型扩展
├── error.rs          # 错误定义
├── traits.rs         # 通用 trait 定义
└── utils/            # 工具函数
    ├── address.rs    # 行地址管理
    └── tracing.rs    # 追踪与日志

关键导出

rust 复制代码
pub const ROW_ID: &str = "_rowid";
pub const ROW_ADDR: &str = "_row_addr";

pub trait Container: Send + Sync {
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

2. lance-file - 文件格式与元数据

职责

  • Lance 文件格式的读写
  • Manifest 管理
  • 文件元数据解析
  • Fragment 的持久化

核心文件

rust 复制代码
src/
├── format.rs         # Lance 文件格式定义
├── manifest.rs       # Manifest 结构
├── reader.rs         # 文件读取器
├── writer.rs         # 文件写入器
├── datatypes.rs      # 数据类型序列化
└── v2/               # V2 文件格式实现
    ├── reader.rs
    └── writer.rs

文件结构

sql 复制代码
┌──────────────────────┐
│   Lance 数据文件       │
├──────────────────────┤
│   PageHeader 0       │
├──────────────────────┤
│   Data Blocks        │
├──────────────────────┤
│   PageHeader 1       │
├──────────────────────┤
│   Data Blocks        │
├──────────────────────┤
│   Manifest           │
├──────────────────────┤
│   Metadata Offset    │
└──────────────────────┘

3. lance-encoding - 编码与解压缩

职责

  • 实现多种编码算法(Bitpacking、Dictionary、Delta 等)
  • 压缩算法集成(LZ4、Zstd)
  • 编码器/解码器接口
  • 向量量化编码

核心模块

rust 复制代码
pub mod encodings {
    pub mod bitpacking;     # Bitpacking 编码
    pub mod dictionary;     # 字典编码
    pub mod delta;          # Delta 编码
    pub mod rle;            # 游程编码
    pub mod prefix;         # 前缀编码
}

pub mod compression {
    pub mod lz4;            # LZ4 压缩
    pub mod zstd;           # Zstd 压缩
}

pub mod encoder;           # 编码器接口
pub mod decoder;           # 解码器接口

4. lance-io - IO 抽象与调度

职责

  • 对象存储抽象(ObjectStore)
  • 多云支持(AWS S3、Azure、GCS、OSS)
  • 本地文件系统优化
  • IO 调度与性能优化

核心接口

rust 复制代码
pub trait ObjectStore: Send + Sync {
    async fn get(&self, location: &Path) -> Result<Bytes>;
    async fn put(&self, location: &Path, bytes: Bytes) -> Result<()>;
    async fn list(&self, prefix: &Path) -> Result<Vec<Path>>;
}

pub struct ObjectStoreParams {
    pub bucket: String,
    pub prefix: String,
    pub region: Option<String>,
    pub options: HashMap<String, String>,
}

5. lance-index - 索引系统

职责

  • 向量索引实现(IVF、HNSW、FLAT)
  • 标量索引实现(BTree、Bitmap)
  • 索引生命周期管理
  • 量化算法

模块结构

rust 复制代码
pub mod vector {
    pub mod ivf;           # IVF 索引
    pub mod hnsw;          # HNSW 索引
    pub mod flat;          # FLAT 索引(无索引)
}

pub mod scalar {
    pub mod btree;         # B-Tree 索引
    pub mod bitmap;        # Bitmap 索引
    pub mod inverted;      # 倒排索引
}

pub mod quantizer;         # 量化器
pub mod kmeans;            # K-Means 聚类

6. lance-table - 表管理与事务

职责

  • Manifest 格式定义
  • 事务与提交协议
  • RowID 管理
  • 版本控制

核心结构

rust 复制代码
pub struct Manifest {
    pub version: u64,
    pub created_at: i64,
    pub fragments: Vec<Fragment>,
    pub schema: Schema,
    pub deletions: Vec<DeletionFile>,
    pub index_metadata: Vec<IndexMetadata>,
}

pub struct Transaction {
    pub base_version: u64,
    pub operations: Vec<Operation>,
    pub schema_changes: Option<SchemaChange>,
}

pub enum Operation {
    Write(WriteOperation),
    Delete(DeleteOperation),
    Update(UpdateOperation),
}

7. lance-datafusion - 查询引擎集成

职责

  • DataFusion ExecutionPlan 实现
  • LogicalPlan 扩展
  • 自定义 UDF 支持
  • 向量搜索 SQL 函数

集成点

rust 复制代码
pub struct LanceScanExec {
    pub dataset: Arc<Dataset>,
    pub schema: SchemaRef,
    pub projection: Option<Vec<usize>>,
    pub filters: Vec<Expr>,
    pub limit: Option<usize>,
}

pub fn vector_search_udf() -> ScalarUDF {
    // 支持 SELECT * FROM table WHERE vector_search(embedding, query, k=10)
}

8. lance-linalg - 线性代数运算

职责

  • 向量距离计算(L2、余弦、内积)
  • 矩阵运算优化
  • SIMD 加速
  • 量化距离近似

关键实现

rust 复制代码
pub enum DistanceType {
    L2,        # 欧氏距离
    Cosine,    # 余弦距离
    DotProduct,# 内积
}

pub trait Distance: Send + Sync {
    fn distance(&self, a: &[f32], b: &[f32]) -> f32;
    fn batch_distance(&self, a: &[f32], b: &[f32]) -> Vec<f32>;
}

模块依赖关系图

perl 复制代码
lance (主包)
├── 依赖
│   ├── lance-core          # 基础类型
│   ├── lance-datafusion    # 查询引擎
│   ├── lance-encoding      # 编码
│   ├── lance-file          # 文件格式
│   ├── lance-io            # IO 抽象
│   ├── lance-index         # 索引
│   ├── lance-table         # 表管理
│   └── lance-linalg        # 线性代数
│
lance-datafusion
├── 依赖
│   ├── lance-core
│   ├── lance-file
│   ├── lance-index
│   └── datafusion (外部)
│
lance-index
├── 依赖
│   ├── lance-core
│   ├── lance-linalg
│   └── lance-io
│
lance-encoding
├── 依赖
│   ├── lance-core
│   ├── lz4 (外部)
│   └── zstd (外部)
│
lance-file
├── 依赖
│   ├── lance-core
│   ├── lance-encoding
│   └── lance-io
│
lance-io
├── 依赖
│   ├── lance-core
│   ├── object_store (外部)
│   └── 云 SDK
│
lance-table
├── 依赖
│   └── lance-core
│
lance-linalg
└── 依赖
    └── lance-core

为什么采用这样的模块划分

1. 关注点分离(Separation of Concerns)

每个模块专注于一个清晰的功能领域:

模块 单一职责
lance-core 类型系统与基础抽象
lance-file 文件格式规范
lance-encoding 数据编码方案
lance-io 存储后端集成
lance-index 查询加速索引
lance-table 版本与事务管理
lance-datafusion SQL 与查询执行
lance-linalg 数学计算优化

2. 独立可测试性

模块化的设计使得:

  • 每个模块可以独立编写单元测试
  • 测试不依赖于其他模块的实现细节
  • 便于 mock 和 stub 的使用

3. 灵活的功能组合

rust 复制代码
// 可以仅使用编码库
use lance_encoding::{Encoder, Decoder};

// 可以仅使用 IO 库
use lance_io::object_store::ObjectStore;

// 可以组合构建完整系统
use lance::{Dataset, dataset::WriteParams};

4. 降低编译耦合

  • 修改某个模块代码只需要重新编译该模块
  • 使用 Cargo workspace 特性并行编译
  • 减少完整编译时间

Cargo 工作区配置

workspace 根配置(Cargo.toml)

toml 复制代码
[workspace]
members = [
    "rust/lance-core",
    "rust/lance-file",
    "rust/lance-encoding",
    "rust/lance-io",
    "rust/lance-index",
    "rust/lance-table",
    "rust/lance-datafusion",
    "rust/lance-linalg",
    "rust/lance",
]
resolver = "2"

[workspace.package]
version = "0.4.0"
edition = "2021"
authors = ["Lance Authors"]
license = "Apache-2.0"
repository = "https://github.com/lancedb/lance"

主包依赖配置

toml 复制代码
# rust/lance/Cargo.toml
[dependencies]
lance-arrow = { workspace = true }
lance-core = { workspace = true }
lance-datafusion = { workspace = true }
lance-encoding = { workspace = true }
lance-file = { workspace = true }
lance-io = { workspace = true }
lance-linalg = { workspace = true }
lance-index = { workspace = true }
lance-table = { workspace = true }

datafusion = { version = "36", features = ["parquet"] }
arrow = { version = "50", features = ["compute"] }
arrow-schema = { version = "50" }
parquet = { version = "50", features = ["arrow"] }

[features]
default = ["aws", "azure", "gcp", "oss"]
aws = ["lance-io/aws"]
azure = ["lance-io/azure"]
gcp = ["lance-io/gcp"]
oss = ["lance-io/oss"]

Python 绑定层架构

PyO3 绑定结构

bash 复制代码
python/
├── lance/
│   ├── __init__.py          # 包入口
│   ├── _lib.pyi             # Rust 绑定类型定义
│   ├── dataset.py           # Dataset 包装
│   ├── table.py             # Table 包装
│   ├── scanner.py           # Scanner 包装
│   ├── index.py             # 索引相关
│   └── errors.py            # 错误定义
├── lance_native/
│   └── _lib.so/.pyd         # Rust 编译后的二进制
└── setup.py                 # 打包配置

PyO3 绑定示例

rust 复制代码
// rust/lance/src/lib.rs
use pyo3::prelude::*;

#[pymodule]
fn _lance(py: Python, m: &PyModule) -> PyResult<()> {
    // 导出 Dataset 类
    m.add_class::<PyDataset>()?;
    
    // 导出 Scanner 类
    m.add_class::<PyScanner>()?;
    
    // 导出模块函数
    m.add_function(wrap_pyfunction!(open_dataset, m)?)?;
    
    Ok(())
}

#[pyclass]
pub struct PyDataset {
    inner: Arc<Dataset>,
}

#[pymethods]
impl PyDataset {
    #[new]
    fn new(uri: &str) -> PyResult<Self> {
        // 初始化
    }
    
    fn scan(&self) -> PyResult<PyScanner> {
        // 返回扫描器
    }
}

模块间通信模式

1. 向下通信(高层调用低层)

scss 复制代码
Dataset API
    ↓
lance-datafusion (查询引擎)
    ↓
lance-index (索引查询)
    ↓
lance-file (数据读取)
    ↓
lance-encoding (解码)
    ↓
lance-io (IO 操作)
    ↓
ObjectStore (云存储)

2. 向上回调(低层报告给高层)

rust 复制代码
// lance-io 通过 callback 向上报告进度
pub trait ProgressCallback: Send + Sync {
    fn on_bytes_read(&self, bytes: u64);
    fn on_rows_processed(&self, rows: u64);
}

// lance-encoding 报告压缩率
pub struct CompressionStats {
    pub original_size: u64,
    pub compressed_size: u64,
    pub compression_ratio: f64,
}

3. 跨层通信(通过共享结构)

rust 复制代码
// 所有层都使用 Arrow Schema 进行通信
use arrow_schema::Schema;

pub struct ColumnInfo {
    pub name: String,
    pub dtype: DataType,
    pub encoding: EncodingType,
    pub compression: CompressionType,
}

pub struct PageMetadata {
    pub num_rows: u32,
    pub num_bytes: u64,
    pub statistics: ColumnStatistics,
}

构建与编译流程

编译优化

bash 复制代码
# 并行编译所有依赖
cargo build --release -j $(nproc)

# 仅编译特定模块
cargo build -p lance-encoding --release

# 启用优化特性
cargo build --release --features="fp16kernels,dynamodb"

特性条件编译

rust 复制代码
#[cfg(feature = "dynamodb")]
pub mod dynamodb_lock;

#[cfg(feature = "fp16kernels")]
pub mod fp16_distance;

#[cfg(not(feature = "aws"))]
compile_error!("AWS support is required");

下一章将详细介绍 Lance 的数据类型系统,探讨如何在 Arrow 基础上进行扩展以支持多模态数据。

相关推荐
语落心生2 小时前
探秘新一代向量存储格式Lance-format (一)Lance 项目概览与设计理念
架构
TracyCoder1232 小时前
微服务注册中心基础(一):AP架构原理
微服务·云原生·架构·注册中心
Kapaseker2 小时前
十年开发告诉你什么是“烂代码”
架构
Java烘焙师3 小时前
架构师必备:限流方案选型(原理篇)
架构·限流·源码分析
爱吃牛肉的大老虎9 小时前
网络传输架构之GraphQL讲解
后端·架构·graphql
Curvatureflight13 小时前
GPT-4o Realtime 之后:全双工语音大模型如何改变下一代人机交互?
人工智能·语言模型·架构·人机交互
t***D26415 小时前
云原生架构
云原生·架构
jinxinyuuuus16 小时前
局域网文件传输:P2P架构中NAT穿透、打洞与数据安全协议
网络协议·架构·p2p
六行神算API-天璇17 小时前
架构实战:打造基于大模型的“混合搜索”系统,兼顾关键词与语义
人工智能·架构