usearch Python API快速入门:5分钟实现向量添加与检索
你是否还在为高维向量检索的性能问题困扰?是否需要一个简单易用却高效的向量搜索引擎?本文将带你5分钟内快速掌握usearch Python API,从安装到实现完整的向量添加与检索流程,让你轻松应对向量检索任务。
读完本文后,你将能够:
- 安装并配置usearch Python环境
- 创建向量索引并添加向量数据
- 执行精确与近似向量检索
- 实现索引的持久化与加载
- 掌握批量操作与性能优化技巧
1. 环境准备与安装
1.1 系统要求
usearch支持多种操作系统和Python版本:
- 操作系统:Linux、Windows、macOS
- Python版本:3.7及以上
- 硬件加速:支持AVX2指令集的CPU可获得最佳性能
1.2 快速安装
使用pip命令即可完成安装:
pip install usearch
如需从源码构建(适用于开发或特定版本需求):
git clone https://gitcode.com/gh_mirrors/us/usearch
cd usearch/python
pip install .
1.3 验证安装
安装完成后,通过以下代码验证:
import usearch
from usearch.index import Index
print(f"usearch version: {usearch.__version__}")
print(f"支持的距离度量: {usearch.index.MetricKind.__members__.keys()}")
预期输出应包含版本信息及支持的距离度量列表,如Cos、IP、L2sq等。
2. 核心概念与基础架构
2.1 核心组件
usearch Python API的核心组件包括:
| 组件 | 描述 |
|---|---|
Index | 向量索引主类,负责向量的存储、索引和检索 |
MetricKind | 距离度量类型枚举,如余弦相似度、内积、欧氏距离等 |
ScalarKind | 标量类型枚举,控制向量存储精度(f32、f16、bf16、i8等) |
Matches | 检索结果容器,包含匹配的向量ID和距离值 |
BatchMatches | 批量检索结果容器,支持多查询向量的检索结果 |
2.2 工作原理
usearch采用分层 navigable small world (HNSW) 图算法,结合SIMD硬件加速,实现高效的近似最近邻搜索。其核心工作流程如下:
HNSW算法通过构建多层图结构,在保证检索质量的同时显著提升检索速度,相比传统方法具有更高的性能。
3. 快速入门:从创建到检索
3.1 创建向量索引
首先,我们需要创建一个向量索引。以下是创建索引的基本示例:
import numpy as np
from usearch.index import Index, MetricKind, ScalarKind
# 创建索引实例
index = Index(
ndim=384, # 向量维度
metric=MetricKind.Cos, # 距离度量:余弦相似度
dtype=ScalarKind.F32, # 存储精度:32位浮点数
connectivity=16, # HNSW图连接数
expansion_add=128, # 添加时的搜索扩展
expansion_search=64 # 检索时的搜索扩展
)
print(f"索引创建成功: 维度={index.ndim}, 度量={index._metric_kind}, 类型={index.dtype}")
参数说明:
| 参数 | 描述 | 默认值 |
|---|---|---|
ndim | 向量维度 | 0(动态确定) |
metric | 距离度量类型 | MetricKind.Cos(余弦相似度) |
dtype | 存储数据类型 | 自动选择(基于度量和硬件) |
connectivity | HNSW图中每个节点的连接数 | 16 |
expansion_add | 添加向量时的搜索扩展 | 128 |
expansion_search | 检索时的搜索扩展 | 64 |
3.2 添加向量
创建索引后,可以向其中添加向量。usearch支持单向量和批量向量添加:
# 生成示例数据
n_vectors = 10000
keys = np.arange(n_vectors, dtype=np.uint64) # 向量ID
vectors = np.random.rand(n_vectors, index.ndim).astype(np.float32) # 随机向量
# 批量添加向量
index.add(keys, vectors, threads=4) # 使用4线程加速
print(f"添加完成: 索引大小={len(index)}, 维度={index.ndim}")
性能提示:
- 使用
threads参数指定并行线程数(0表示自动检测) - 对于大型数据集,设置
copy=False可避免数据复制(需确保向量数据生命周期覆盖索引使用期) - 添加进度可通过
log=True参数启用进度条
3.3 向量检索
添加向量后,即可执行检索操作。usearch支持精确检索和近似检索:
# 生成查询向量
query_vector = np.random.rand(index.ndim).astype(np.float32)
# 近似检索(默认)
results = index.search(query_vector, count=10) # 返回前10个结果
print(f"检索完成: 找到{len(results)}个结果")
print("前5个结果:")
for i, match in enumerate(results[:5]):
print(f" 排名{i+1}: ID={match.key}, 距离={match.distance:.4f}")
# 精确检索(用于小数据集或验证)
exact_results = index.search(query_vector, count=10, exact=True)
检索结果解析:
search方法返回Matches对象,包含以下属性:
keys: 匹配的向量ID数组distances: 对应的距离值数组visited_members: 访问的节点数computed_distances: 计算的距离数
3.4 索引持久化与加载
usearch支持索引的保存与加载,方便后续使用:
# 保存索引
index.save("my_index.usearch")
print("索引已保存")
# 加载索引
new_index = Index.restore("my_index.usearch")
print(f"索引加载成功: 大小={len(new_index)}, 维度={new_index.ndim}")
# 内存映射(适合大型索引,无需全部加载到内存)
mapped_index = Index()
mapped_index.view("my_index.usearch")
print(f"内存映射索引: 大小={len(mapped_index)}")
持久化选项:
save(path): 将索引完整保存到磁盘load(path): 从磁盘加载索引到内存view(path): 创建磁盘索引的内存映射视图(只读)Index.metadata(path): 获取索引元数据(无需加载整个索引)
4. 高级功能
4.1 批量操作
usearch对批量操作进行了优化,推荐在处理大量数据时使用:
# 批量添加
n_batch = 1000
batch_keys = np.arange(n_batch, dtype=np.uint64)
batch_vectors = np.random.rand(n_batch, index.ndim).astype(np.float32)
index.add(batch_keys, batch_vectors)
# 批量检索
n_queries = 100
query_vectors = np.random.rand(n_queries, index.ndim).astype(np.float32)
batch_results = index.search(query_vectors, count=10)
print(f"批量检索完成: 查询数={len(batch_results)}, 每个查询结果数={len(batch_results[0])}")
# 处理第一个查询的结果
first_query_results = batch_results[0]
print(f"第一个查询结果: {[(match.key, match.distance) for match in first_query_results[:3]]}")
4.2 距离度量选择
usearch支持多种距离度量,适用于不同场景:
# 查看所有支持的距离度量
print("支持的距离度量:", [m for m in MetricKind.__members__.keys()])
# 创建不同度量的索引示例
index_ip = Index(ndim=128, metric=MetricKind.IP) # 内积
index_l2 = Index(ndim=128, metric=MetricKind.L2sq) # 平方欧氏距离
index_hamming = Index(ndim=256, metric=MetricKind.Hamming) # 汉明距离
print(f"创建不同度量的索引: IP={index_ip._metric_kind}, L2={index_l2._metric_kind}, Hamming={index_hamming._metric_kind}")
常用度量适用场景:
| 度量类型 | 适用场景 | 向量类型 |
|---|---|---|
Cos(余弦相似度) | 文本、图像特征 | 单位向量 |
IP(内积) | 推荐系统、分类任务 | 归一化向量 |
L2sq(平方欧氏距离) | 高维数据检索 | 任意实值向量 |
Hamming(汉明距离) | 二进制特征 | 二进制向量 |
4.3 数据类型优化
usearch支持多种数据类型,可根据精度需求和性能要求选择:
# 创建不同数据类型的索引
index_f16 = Index(ndim=128, dtype=ScalarKind.F16) # 16位浮点数
index_bf16 = Index(ndim=128, dtype=ScalarKind.BF16) # BF16浮点数
index_i8 = Index(ndim=128, dtype=ScalarKind.I8) # 8位整数
print(f"数据类型比较: F16={index_f16.dtype}, BF16={index_bf16.dtype}, I8={index_i8.dtype}")
# 测试不同数据类型的性能
import time
def test_performance(dtype, n=10000):
index = Index(ndim=128, dtype=dtype)
keys = np.arange(n, dtype=np.uint64)
vectors = np.random.rand(n, 128).astype(np.float32)
start = time.time()
index.add(keys, vectors)
add_time = time.time() - start
query = np.random.rand(128).astype(np.float32)
start = time.time()
index.search(query, 10)
search_time = time.time() - start
return {
"dtype": dtype,
"add_time": add_time,
"search_time": search_time,
"size": len(index)
}
# 测试不同数据类型性能
results = []
for dtype in [ScalarKind.F32, ScalarKind.F16, ScalarKind.BF16, ScalarKind.I8]:
results.append(test_performance(dtype))
print("\n不同数据类型性能比较:")
for res in results:
print(f"{res['dtype']}: 添加时间={res['add_time']:.4f}s, 检索时间={res['search_time']:.4f}s")
数据类型比较:
| 数据类型 | 存储空间 | 精度 | 性能 | 硬件支持 |
|---|---|---|---|---|
F32 | 高 | 高 | 中 | 所有CPU |
F16 | 中 | 中 | 高 | 支持AVX2的CPU |
BF16 | 中 | 中高 | 高 | 现代CPU(Intel Ice Lake+, AMD Zen4+) |
I8 | 低 | 低 | 最高 | 所有CPU |
5. 性能优化与最佳实践
5.1 参数调优
HNSW算法的性能和质量受多个参数影响,以下是调优建议:
# 创建优化的索引
optimized_index = Index(
ndim=256,
metric=MetricKind.Cos,
connectivity=32, # 增加连接数提高召回率
expansion_add=256, # 增加添加扩展提高建索引质量
expansion_search=128 # 增加检索扩展提高召回率
)
参数调优指南:
| 目标 | 调整参数 | 建议值 |
|---|---|---|
| 提高检索速度 | 降低expansion_search | 16-32 |
| 提高召回率 | 提高expansion_search | 64-256 |
| 减少内存占用 | 降低connectivity | 8-16 |
| 提高构建速度 | 降低expansion_add | 32-64 |
| 大型数据集 | 增加connectivity | 16-32 |
5.2 批量操作性能
对于大规模数据处理,批量操作比单次操作效率更高:
# 批量添加性能对比
n = 100000
vectors = np.random.rand(n, 128).astype(np.float32)
keys = np.arange(n, dtype=np.uint64)
# 单次添加
start = time.time()
index_single = Index(ndim=128)
index_single.add(keys, vectors, threads=0)
single_time = time.time() - start
# 分批次添加
start = time.time()
index_batch = Index(ndim=128)
batch_size = 10000
for i in range(0, n, batch_size):
batch_keys = keys[i:i+batch_size]
batch_vectors = vectors[i:i+batch_size]
index_batch.add(batch_keys, batch_vectors, threads=0)
batch_time = time.time() - start
print(f"单次添加: {single_time:.4f}s, 分批次添加: {batch_time:.4f}s")
批量操作最佳实践:
- 批量大小设置为1000-10000(根据向量维度调整)
- 使用多线程加速(
threads参数) - 对于非常大的数据集,考虑分块处理
5.3 精确检索与近似检索对比
usearch支持精确检索(线性扫描)和近似检索(HNSW),可根据需求选择:
# 生成测试数据
n = 10000
dim = 128
index = Index(ndim=dim)
keys = np.arange(n)
vectors = np.random.rand(n, dim).astype(np.float32)
index.add(keys, vectors)
query = vectors[0] # 使用第一个向量作为查询
# 近似检索
start = time.time()
approx_results = index.search(query, count=10)
approx_time = time.time() - start
# 精确检索
start = time.time()
exact_results = index.search(query, count=10, exact=True)
exact_time = time.time() - start
# 计算召回率
approx_ids = set(approx_results.keys)
exact_ids = set(exact_results.keys)
recall = len(approx_ids.intersection(exact_ids)) / len(exact_ids)
print(f"近似检索: 时间={approx_time:.4f}s, 召回率={recall:.4f}")
print(f"精确检索: 时间={exact_time:.4f}s")
检索模式选择建议:
| 模式 | 速度 | 准确率 | 适用场景 |
|---|---|---|---|
| 近似检索(默认) | 快(毫秒级) | 高(可调节) | 大规模数据集、实时应用 |
| 精确检索 | 慢(秒级) | 100% | 小规模数据集、结果验证 |
6. 常见问题与解决方案
6.1 内存占用过大
问题:处理大规模数据集时内存占用过高。
解决方案:
- 使用低精度数据类型(如
F16、BF16或I8) - 启用磁盘内存映射(
view()方法) - 增加
connectivity同时降低expansion_add和expansion_search
# 使用内存映射减少内存占用
index.view("large_index.usearch") # 仅映射元数据,不加载完整索引
6.2 检索速度慢
问题:检索操作耗时过长,无法满足实时需求。
解决方案:
- 降低
expansion_search参数 - 减少返回结果数量(
count参数) - 使用低精度数据类型
- 增加线程数(
threads参数)
# 优化检索速度
fast_results = index.search(query, count=5, expansion_search=16, threads=4)
6.3 索引构建时间长
问题:大规模数据集索引构建耗时过长。
解决方案:
- 降低
expansion_add参数 - 增加
threads参数使用更多CPU核心 - 分批次添加并监控进度
# 加速索引构建
index.add(keys, vectors, expansion_add=32, threads=8)
7. 总结与后续学习
7.1 核心功能回顾
本文介绍了usearch Python API的核心功能:
- 索引创建与配置
- 向量添加(单向量和批量)
- 向量检索(精确和近似)
- 索引持久化与加载
- 性能优化与参数调优
通过这些功能,你可以快速实现高效的向量检索系统,满足从中小规模到大规模数据集的需求。
7.2 进阶学习路径
掌握基础后,可进一步学习:
- 自定义距离函数:使用Numba或Cppyy实现自定义距离度量
- 分布式检索:结合usearch的分布式功能实现大规模集群检索
- 混合索引:结合其他索引结构(如FAISS)构建混合检索系统
- 应用集成:与PyTorch/TensorFlow集成实现端到端的向量检索系统
7.3 资源推荐
- 官方文档:usearch GitHub仓库
- 示例代码:仓库中
python/scripts目录下的示例和测试代码 - 性能基准:
BENCHMARKS.md文件包含详细性能对比数据 - 社区支持:通过GitHub Issues提交问题和功能请求
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



