Rust高效向量搜索库usearch的使用,usearch提供快速相似性搜索和近似最近邻算法实现

Rust高效向量搜索库usearch的使用

USearch是一个小型且快速的单文件相似性搜索和聚类引擎,用于向量和文本数据。它提供了以下主要特性:

  • 比FAISS快10倍的HNSW实现
  • 简单且可扩展的C++11单头文件库
  • 支持用户自定义度量标准
  • 硬件无关的f16和i8支持(半精度和四分之一精度)
  • 可以从磁盘查看大型索引而无需加载到RAM
  • 支持异构查找、重命名/重新标记和即时删除

基本用法示例

以下是Rust中使用USearch进行向量搜索的基本示例:

use usearch::ffi::IndexOptions;
use usearch::ffi::MetricKind;
use usearch::Index;

fn main() {
    // 创建索引
    let options = IndexOptions {
        dimensions: 3,
        metric: MetricKind::L2sq,
        quantization: usearch::ffi::ScalarKind::F32,
        connectivity: 0,
        expansion_add: 0,
        expansion_search: 0,
        multi: false,
    };
    
    let mut index = Index::new(options).unwrap();
    
    // 添加向量
    let key: u64 = 42;
    let vector = vec![0.2, 0.6, 0.4];
    index.add(key, &vector).unwrap();
    
    // 搜索相似向量
    let results = index.search(&vector, 10).unwrap();
    
    assert_eq!(results.keys[0], key);
    assert!(results.distances[0] <= 0.001);
}

过滤搜索示例

USearch支持在搜索过程中应用过滤谓词:

let is_odd = |key: u64| key % 2 == 1;
let query = vec![0.2, 0.1, 0.2, 0.1, 0.3];
let results = index.filtered_search(&query, 10, is_odd).unwrap();

assert!(
    results.keys.iter().all(|&key| key % 2 == 1),
    "All keys must be odd"
);

完整示例代码

以下是一个更完整的Rust示例,展示USearch的更多功能:

use usearch::ffi::{IndexOptions, MetricKind, ScalarKind};
use usearch::Index;
use rand::Rng;

fn main() {
    // 配置索引参数
    let options = IndexOptions {
        dimensions: 128,
        metric: MetricKind::Cos,
        quantization: ScalarKind::F16,
        connectivity: 16,
        expansion_add: 128,
        expansion_search: 64,
        multi: false,
    };
    
    // 创建索引
    let mut index = Index::new(options).unwrap();
    
    // 生成1000个随机向量并添加到索引
    let mut rng = rand::thread_rng();
    for i in 0..1000 {
        let vector: Vec<f32> = (0..128).map(|_| rng.gen()).collect();
        index.add(i, &vector).unwrap();
    }
    
    // 生成查询向量
    let query: Vec<f32> = (0..128).map(|_| rng.gen()).collect();
    
    // 执行搜索并获取前10个最相似结果
    let results = index.search(&query, 10).unwrap();
    
    println!("最相似的10个向量:");
    for i in 0..results.count {
        println!("ID: {}, 距离: {}", results.keys[i], results.distances[i]);
    }
    
    // 保存索引到文件
    index.save("data.usearch").unwrap();
    
    // 从文件加载索引
    let loaded_index = Index::load("data.usearch").unwrap();
    
    // 使用加载的索引进行搜索
    let new_results = loaded_index.search(&query, 5).unwrap();
    println!("从加载索引中获取的5个结果:");
    for i in 0..new_results.count {
        println!("ID: {}, 距离: {}", new_results.keys[i], new_results.distances[i]);
    }
    
    // 使用过滤搜索
    let is_even = |key: u64| key % 2 == 0;
    let filtered_results = loaded_index.filtered_search(&query, 5, is_even).unwrap();
    println!("偶数ID的结果:");
    for i in 0..filtered_results.count {
        println!("ID: {}, 距离: {}", filtered_results.keys[i], filtered_results.distances[i]);
    }
}

性能优化建议

  1. 对于大型数据集,考虑使用ScalarKind::BF16ScalarKind::F16来减少内存使用
  2. 调整connectivity参数可以影响索引构建时间和搜索质量
  3. expansion_addexpansion_search参数可以控制召回率和搜索速度的平衡

USearch支持的距离度量包括:

  • 欧几里得距离(L2sq)
  • 内积(IP)
  • 余弦相似度(Cos)
  • 哈弗辛距离(Haversine)
  • 自定义距离函数

这个库非常适合需要高效向量搜索的应用场景,如:

  • 推荐系统
  • 图像检索
  • 文本相似性搜索
  • 语义搜索
  • 聚类分析

1 回复

以下是基于您提供的usearch库使用指南的完整示例代码,演示了从创建索引到搜索相似向量的完整流程:

use usearch::Index;

fn main() {
    // 1. 创建索引
    let dimensions = 128; // 向量维度
    let mut index = Index::options()
        .dimensions(dimensions)
        .metric("cos") // 使用余弦相似度
        .quantization("f32") // 使用f32量化
        .connectivity(16) // 连接性参数
        .build()
        .unwrap();
    
    println!("索引创建成功");

    // 2. 添加一些示例向量
    let vectors = vec![
        vec![0.1; dimensions], // 向量1
        vec![0.2; dimensions], // 向量2
        vec![0.3; dimensions], // 向量3
    ];
    
    let keys = vec![1, 2, 3]; // 向量对应的唯一ID
    
    // 批量添加向量
    index.extend(&keys, &vectors).unwrap();
    println!("成功添加了{}个向量", keys.len());

    // 3. 搜索相似向量
    let query_vector = vec![0.15; dimensions]; // 查询向量
    let k = 2; // 返回2个最相似的结果
    
    let results = index.search(&query_vector, k).unwrap();
    
    println!("最相似的{}个结果:", k);
    for result in results {
        println!("ID: {}, 距离: {:.4}", result.key, result.distance);
    }

    // 4. 保存和加载索引
    let save_path = "example_index.usearch";
    index.save(save_path).unwrap();
    println!("索引已保存到: {}", save_path);
    
    // 从文件加载索引
    let loaded_index = Index::load(save_path).unwrap();
    println!("索引加载成功");

    // 5. 使用加载的索引进行搜索
    let new_results = loaded_index.search(&query_vector, k).unwrap();
    println!("使用加载的索引搜索的结果:");
    for result in new_results {
        println!("ID: {}, 距离: {:.4}", result.key, result.distance);
    }
}

这个完整示例演示了:

  1. 使用Index::options()创建可配置的索引
  2. 使用extend()方法批量添加多个向量
  3. 使用search()方法查询相似向量
  4. 使用save()load()方法持久化索引
  5. 展示了完整的搜索工作流程

代码中的注释详细解释了每个步骤的作用,您可以直接运行这个示例来体验usearch的基本功能。根据实际需求,您可以调整维度数、距离度量类型等参数来优化性能。

回到顶部