现代化的列式数据格式,专为机器学习设计。只需两行代码即可从 Parquet 格式转换,实现随机访问速度提升 100 倍、向量索引、数据版本控制等功能。
兼容 pandas、DuckDB、Polars 和 pyarrow,更多集成正在路上。
Lance 是一种现代化的列式数据格式,优化用于机器学习工作流和数据集。Lance 完美适用于:
- 构建搜索引擎和特征库。
- 大规模机器学习训练,要求高性能的 IO 和数据洗牌。
- 存储、查询和检查复杂嵌套数据,如机器人技术中的大型数据块(如图像、点云等)。
Lance 的关键特性包括:
-
高性能随机访问: 速度比 Parquet 快 100 倍,且不牺牲扫描性能。
-
向量搜索: 在毫秒级别内找到最近邻,并将 OLAP 查询与向量搜索相结合。
-
零拷贝、自动版本控制: 无需额外基础设施即可管理数据版本。
-
生态系统集成: 支持 Apache Arrow、Pandas、Polars、DuckDB 等,更多集成正在开发中。
[!TIP] Lance 处于积极开发中,欢迎贡献。请参阅我们的 贡献指南 以了解更多信息。
快速入门
安装
pip install pylance
安装预览版:
pip install --pre --extra-index-url https://pypi.fury.io/lancedb/ pylance
[!TIP] 预览版的发布频率高于正式版,包含最新的功能和修复。我们保证这些版本将在至少 6 个月内保持可下载。当您需要固定到特定版本时,请优先选择稳定版本。
转换为 Lance 格式
import lance
import pandas as pd
import pyarrow as pa
import pyarrow.dataset
df = pd.DataFrame({"a": [5], "b": [10]})
uri = "/tmp/test.parquet"
tbl = pa.Table.from_pandas(df)
pa.dataset.write_dataset(tbl, uri, format='parquet')
parquet = pa.dataset.dataset(uri, format='parquet')
lance.write_dataset(parquet, "/tmp/test.lance")
读取 Lance 数据
dataset = lance.dataset("/tmp/test.lance")
assert isinstance(dataset, pa.dataset.Dataset)
Pandas
df = dataset.to_table().to_pandas()
df
DuckDB
import duckdb
# 如果发生段错误,请确保安装了 duckdb v0.7+
duckdb.query("SELECT * FROM dataset LIMIT 10").to_df()
向量搜索
下载 sift1m 子集
wget ftp://ftp.irisa.fr/local/texmex/corpus/sift.tar.gz
tar -xzf sift.tar.gz
将其转换为 Lance 格式
import lance
from lance.vector import vec_to_table
import numpy as np
import struct
nvecs = 1000000
ndims = 128
with open("sift/sift_base.fvecs", mode="rb") as fobj:
buf = fobj.read()
data = np.array(struct.unpack("<128000000f", buf[4 : 4 + 4 * nvecs * ndims])).reshape((nvecs, ndims))
dd = dict(zip(range(nvecs), data))
table = vec_to_table(dd)
uri = "vec_data.lance"
sift1m = lance.write_dataset(table, uri, max_rows_per_group=8192, max_rows_per_file=1024*1024)
建立索引
sift1m.create_index("vector",
index_type="IVF_PQ",
num_partitions=256, # IVF
num_sub_vectors=16) # PQ
搜索数据集
# 获取前 10 个相似向量
import duckdb
dataset = lance.dataset(uri)
# 抽取 100 个查询向量。如果发生段错误,请确保安装了 duckdb v0.7+
sample = duckdb.query("SELECT vector FROM dataset USING SAMPLE 100").to_df()
query_vectors = np.array([np.array(x) for x in sample.vector])
# 获取所有查询向量的最近邻
rs = [dataset.to_table(nearest={"column": "vector", "k": 10, "q": q})
for q in query_vectors]
目录结构
Lance 的独特之处
以下是 Lance 设计的几个方面,更多详情请参阅完整的 Lance 设计文档。
向量索引: 用于在嵌入空间进行相似性搜索的向量索引。
支持 CPU(x86_64
和 arm
)和 GPU(Nvidia (cuda)
和 Apple Silicon (mps)
)。
编码: 为实现快速列式扫描和子线性点查询,Lance 使用了自定义编码和布局。
嵌套字段: Lance 将每个子字段存储为独立列,以支持高效过滤,例如“查找检测到包含猫的图像”。
版本控制: 可以使用 Manifest 记录快照。目前我们支持通过追加、覆盖和索引创建来自动生成新版本。
快速更新(路线图):更新将通过写前日志来支持。
丰富的二级索引(路线图):
- 用于标签/注释字段模糊搜索的倒排索引。
基准测试
向量搜索
我们使用 SIFT 数据集对 1M 个 128 维向量进行了基准测试
- 对于 100 个随机抽样的查询向量,我们的平均响应时间 <1ms(在 2023 年的 M2 MacBook Air 上)
- 近似最近邻搜索(ANN)总是在召回率和性能之间进行权衡
与 Parquet 的对比
我们使用 Oxford Pet 数据集创建了 Lance 数据集,以初步测试 Lance 相比 Parquet 和原始图像/XML 的性能。在分析查询中,Lance 的性能比读取原始元数据快 50-100 倍。在批量随机访问中,Lance 比 Parquet 和原始文件快 100 倍。
为什么要创建一种新的数据格式?!
机器学习开发周期包括以下步骤:
graph LR
A[数据收集] --> B[数据探索];
B --> C[数据分析];
C --> D[特征工程];
D --> E[模型训练];
E --> F[模型评估];
F --> C;
E --> G[模型部署];
G --> H[模型监控];
H --> A;
人们在不同阶段使用不同的数据表示形式以获得最佳性能或受到可用工具的限制。 学术界主要使用 XML/JSON 来进行注释,并使用压缩图像/传感器数据进行深度学习,这难以集