第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 基础上进行扩展以支持多模态数据。