Project Icon

usearch

快速轻量的开源向量搜索引擎

USearch是一个开源的单文件相似性搜索引擎,专注于向量和文本搜索。该引擎比FAISS性能提升10倍,支持多种编程语言和平台。USearch提供SIMD优化和自定义度量功能,具有高内存效率,可从磁盘直接查看大型索引。它兼容多种数据库,适用于语义搜索、聚类等场景,为向量搜索提供了灵活高效的解决方案。

USearch

更小 & 更快 的单文件
向量 & 🔜 文本 相似度搜索引擎


Discord     LinkedIn     Twitter     博客     GitHub

空间 • 二进制 • 概率 • 用户自定义度量
C++ 11Python 3JavaScriptJavaRustC 99Objective-CSwiftC#GoLangWolfram
Linux • MacOS • Windows • iOS • WebAssembly • SQLite3


__技术洞察__和相关文章:

与FAISS的比较

FAISS是广受认可的高性能向量搜索引擎标准。 USearch和FAISS都使用相同的HNSW算法,但在设计原则上有显著差异。 USearch在不牺牲性能的情况下更加紧凑和广泛兼容,主要关注用户自定义度量和更少的依赖。

FAISSUSearch改进
索引时间 ⁰
1亿个96维 f32f16i8 向量2.6 · 2.6 · 2.6 h0.3 · 0.2 · 0.2 h9.6 · 10.4 · 10.7 x
1亿个1536维 f32f16i8 向量5.0 · 4.1 · 3.8 h2.1 · 1.1 · 0.8 h2.3 · 3.6 · 4.4 x
代码库长度 ¹84 K SLOC3 K SLOC可维护
支持的度量 ²9种固定度量任意度量可扩展
支持的语言 ³C++, Python10种语言可移植
支持的ID类型 ⁴32位, 64位32位, 40位, 64位高效率
过滤 ⁵禁用列表任意谓词可组合
所需依赖 ⁶BLAS, OpenMP-轻量级
绑定 ⁷SWIG原生低延迟
Python绑定大小 ⁸~ 10 MB< 1 MB易部署

⁰ 在Intel Sapphire Rapids上测试,使用最简单的内积距离,等效召回率和内存消耗,同时还提供了更优的搜索速度。 ¹ usearch/相比faiss/更短的代码库使项目更易于维护和审核。 ² 用户自定义度量允许你为各种应用定制搜索,从GIS到为多个AI模型的复合嵌入或混合全文和语义搜索创建自定义度量。 ³ 使用USearch,你可以在各种编程语言中重用同一个预构建索引。 ⁴ 40位整数允许你存储超过4B个向量,而无需为邻近图中的每个邻居引用分配8字节。 ⁵ 使用USearch,索引可以与任意外部容器(如布隆过滤器或第三方数据库)结合,在索引遍历期间过滤掉不相关的键。 ⁶ 缺少必要的依赖使USearch更加可移植。 ⁷ 原生绑定比更简单的方法引入更低的调用延迟。 ⁸ 更轻量的绑定使下载和部署更快。

基本功能与FAISS相同,如果你曾研究过近似最近邻搜索,接口应该很熟悉:

# pip install numpy usearch

import numpy as np
from usearch.index import Index

index = Index(ndim=3)

vector = np.array([0.2, 0.6, 0.4])
index.add(42, vector)

matches = index.search(vector, 10)

assert matches[0].key == 42
assert matches[0].distance <= 0.001
assert np.allclose(index[42], vector, atol=0.1) # 确保在混合精度比较中使用高容差

更多设置始终可用,API设计旨在尽可能灵活。 默认存储/量化级别取决于硬件以提高效率,但对大多数现代CPU推荐使用f16

index = Index(
    ndim=3, # 定义输入向量的维度数
    metric='cos', # 选择'l2sq'、'ip'、'haversine'或其他度量,默认='cos'
    dtype='f16', # 存储为'f64'、'f32'、'f16'、'i8'、'b1'...,默认=None
    connectivity=16, # 可选:限制每个图节点的邻居数
    expansion_add=128, # 可选:控制索引的召回率
    expansion_search=64, # 可选:控制搜索质量
    multi=False, # 可选:允许每个键多个向量,默认=False
)

序列化和从磁盘服务Index

USearch支持多种序列化形式:

  • 序列化到由路径定义的__文件__中。
  • 序列化到由回调定义的__流__中,逐步序列化或重建。
  • 序列化到固定长度的__缓冲区__或支持随机访问的内存映射文件中。

后者允许你从外部内存提供索引服务,使你能够针对索引速度和服务成本优化服务器选择。 这可以在AWS和其他公共云上实现__20倍的成本降低__。

index.save("index.usearch")

loaded_copy = index.load("index.usearch")
view = Index.restore("index.usearch", view=True)

other_view = Index(ndim=..., metric=...)
other_view.view("index.usearch")

精确与近似搜索

当精确的暴力搜索变得过于资源密集时,通常会使用近似搜索方法,如HNSW。 这通常发生在集合中有数百万个条目时。 对于较小的集合,我们提供了一种更直接的方法,即search方法。

from usearch.index import search, MetricKind, Matches, BatchMatches
import numpy as np
# 生成10'000个随机向量,每个向量有1024个维度
vectors = np.random.rand(10_000, 1024).astype(np.float32)
vector = np.random.rand(1024).astype(np.float32)

one_in_many: Matches = search(vectors, vector, 50, MetricKind.L2sq, exact=True)
many_in_many: BatchMatches = search(vectors, vectors, 50, MetricKind.L2sq, exact=True)

如果传入exact=True参数,系统将完全绕过索引,使用来自SimSIMD的SIMD优化相似度度量,对整个数据集执行暴力搜索。 与FAISS的IndexFlatL2在Google Colab上相比,USearch可能提供高达20倍的性能提升:

  • faiss.IndexFlatL2: 55.3毫秒
  • usearch.index.search: 2.54毫秒

用户自定义度量

虽然大多数向量搜索包只专注于两种度量,即"内积距离"和"欧几里德距离",但USearch允许使用任意用户自定义度量。 这种灵活性使您可以为各种应用定制搜索,从使用罕见的Haversine距离计算地理空间坐标,到为多个AI模型的复合嵌入创建自定义度量,如联合图像-文本嵌入。 您可以使用NumbaCppyyPeachPy在Python中定义自定义度量

from numba import cfunc, types, carray
from usearch.index import Index, MetricKind, MetricSignature, CompiledMetric

@cfunc(types.float32(types.CPointer(types.float32), types.CPointer(types.float32)))
def python_inner_product(a, b):
    a_array = carray(a, ndim)
    b_array = carray(b, ndim)
    c = 0.0
    for i in range(ndim):
        c += a_array[i] * b_array[i]
    return 1 - c

metric = CompiledMetric(pointer=python_inner_product.address, kind=MetricKind.IP, signature=MetricSignature.ArrayArray)
index = Index(ndim=ndim, metric=metric, dtype=np.float32)

在C、C++和Rust接口中实现类似效果甚至更容易。 此外,与KD树和局部敏感哈希等较旧的高维空间索引方法不同,HNSW不要求向量长度相同。 它们只需要可比较。 因此,您可以在奇特的应用中使用它,比如搜索相似集合或模糊文本匹配,使用GZip压缩率作为距离函数。

过滤和谓词函数

有时您可能想要根据某些外部数据库交叉引用搜索结果或根据某些条件过滤它们。 在大多数引擎中,您必须手动执行分页请求,逐步过滤结果。 在USearch中,您只需将谓词函数传递给搜索方法,该函数将直接在图遍历过程中应用。 在Rust中,这看起来像这样:

let is_odd = |key: Key| 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),
    "所有键必须为奇数"
);

内存效率、降精度和量化

训练量化模型和降维是加速向量搜索的常见方法。 然而,这些方法并不总是可靠的,可能会显著影响数据的统计属性,并且如果分布发生变化,需要定期调整。 相反,我们专注于对降精度向量进行高精度运算。 相同的索引、addsearch操作将自动在f64_tf32_tf16_ti8_t和单比特表示之间进行降精度或提升精度。 您可以使用以下命令检查是否启用了硬件加速:

$ python -c 'from usearch.index import Index; print(Index(ndim=768, metric="cos", dtype="f16").hardware_acceleration)'
> sapphire
$ python -c 'from usearch.index import Index; print(Index(ndim=166, metric="tanimoto").hardware_acceleration)'
> ice

使用较小的数值类型将节省存储向量所需的RAM,但您也可以压缩形成我们近邻图的邻居列表。 默认情况下,使用32位的uint32_t来枚举这些列表,但如果需要寻址超过40亿个条目,这是不够的。 对于这种情况,我们提供了一个自定义的uint40_t类型,它仍然比常用的8字节整数节省37.5%的空间,并且可以扩展到1万亿个条目。

USearch uint40_t支持

Indexes用于多索引查找

对于针对数十亿甚至万亿向量的大型工作负载,并行多索引查找变得非常有价值。 您可以构建多个较小的索引,而不是构建一个大型索引,并将它们一起查看。

from usearch.index import Indexes

multi_index = Indexes(
    indexes: Iterable[usearch.index.Index] = [...],
    paths: Iterable[os.PathLike] = [...],
    view: bool = False,
    threads: int = 0,
)
multi_index.search(...)

聚类

一旦构建了索引,USearch可以比独立的聚类库(如SciPy、UMap和tSNE)更快地执行K近邻聚类。 对PCA进行降维也是如此。 本质上,Index本身可以被视为一种聚类,允许迭代深化。

clustering = index.cluster(
    min_count=10, # 可选
    max_count=15, # 可选
    threads=..., # 可选
)

# 获取聚类及其大小
centroid_keys, sizes = clustering.centroids_popularity

# 使用Matplotlib绘制直方图
clustering.plot_centroids_popularity()

# 导出聚类的NetworkX图
g = clustering.network

# 获取特定聚类的成员
first_members = clustering.members_of(centroid_keys[0])

# 深入到该聚类,将其分成更多部分,支持所有相同的参数
sub_clustering = clustering.subcluster(min_count=..., max_count=...)

生成的聚类结果与K-Means或其他传统方法不完全相同,但serve相同的目的。 另外,在使用Scikit-Learn处理100万数据点的数据集时,查询可能需要几分钟到几小时的时间,具体取决于您想要突出显示的聚类数量。 对于50,000个聚类,USearch与传统聚类方法的性能差异可能轻松达到100倍。

连接、一对一、一对多和多对多映射

当今的一个重大问题是人工智能将如何改变数据库和数据管理的世界。 大多数数据库仍在努力实现高质量的模糊搜索,而且它们所知道的唯一连接类型是确定性的。 "连接"与搜索每个条目不同,它需要一对一映射,禁止在不同的搜索结果之间出现冲突。

精确搜索模糊搜索语义搜索?
精确连接模糊连接?语义连接??

使用USearch,可以实现亚二次复杂度的近似、模糊和语义连接。 这在数据库管理软件常见的任何模糊匹配任务中都很有用。

men = Index(...)
women = Index(...)
pairs: dict = men.join(women, max_proposals=0, exact=False)

阅读更多内容,请参阅文章:语义搜索的组合稳定婚姻 💍

功能

目前,所有绑定都支持核心功能。 更广泛的功能按需移植。 在某些情况下,如批处理操作,功能对等是没有意义的,因为宿主语言具有完整的多线程能力,而USearch索引结构在设计上是并发的,因此用户可以以最适合其应用的方式实现批处理/调度/负载平衡。

C++ 11Python 3C 99JavaJavaScriptRustGoLangSwift
添加、搜索、删除
保存、加载、查看
用户自定义度量
批处理操作
过滤谓词
连接
可变长度向量
4B+容量

应用示例

USearch + UForm + UCall = 多模态语义搜索

人工智能有越来越多的应用,但最酷的经典想法之一是将其用于语义搜索。 可以使用多模态编码器模型,如UForm,以及Web编程框架,如UCall,仅用20行Python代码就可以构建一个文本到图像的搜索平台。

from ucall import Server
from uform import get_model, Modality
from usearch.index import Index

import numpy as np
import PIL as pil

processors, models = get_model('unum-cloud/uform3-image-text-english-small')
model_text = models[Modality.TEXT_ENCODER]
model_image = models[Modality.IMAGE_ENCODER]
processor_text = processors[Modality.TEXT_ENCODER]
processor_image = processors[Modality.IMAGE_ENCODER]

server = Server()
index = Index(ndim=256)

@server
def add(key: int, photo: pil.Image.Image):
    image = processor_image(photo)
    vector = model_image(image)
    index.add(key, vector.flatten(), copy=True)

@server
def search(query: str) -> np.ndarray:
    tokens = processor_text(query)
    vector = model_text(tokens)
    matches = index.search(vector.flatten(), 3)
    return matches.keys

server.run()

类似的体验也可以在其他语言和客户端实现,消除网络延迟。 对于Swift和iOS,请查看ashvardanian/SwiftSemanticSearch仓库。

SwiftSemanticSearch演示狗 SwiftSemanticSearch演示花朵

GitHub上提供了一个更完整的Streamlit演示。 我们已预处理了一些常用数据集,清理了图像,生成了向量,并预构建了索引。

数据集模态图像数下载
Unsplash图像和描述25 KHuggingFace / Unum
Conceptual Captions图像和描述3 MHuggingFace / Unum
Arxiv标题和摘要2 MHuggingFace / Unum

USearch + RDKit = 分子搜索

比较分子图和搜索相似结构是昂贵且缓慢的过程。 这可以被视为NP完全子图同构问题的一个特例。 幸运的是,存在针对特定领域的近似方法。 化学领域常用的方法是从SMILES生成结构,然后将其哈希为二进制指纹。 后者可以使用二进制相似度度量(如Tanimoto系数)进行搜索。 以下是使用RDKit包的示例。

from usearch.index import Index, MetricKind
from rdkit import Chem
from rdkit.Chem import AllChem

import numpy as np

molecules = [Chem.MolFromSmiles('CCOC'), Chem.MolFromSmiles('CCO')]
encoder = AllChem.GetRDKitFPGenerator()

fingerprints = np.vstack([encoder.GetFingerprint(x) for x in molecules])
fingerprints = np.packbits(fingerprints, axis=1)

index = Index(ndim=2048, metric=MetricKind.Tanimoto)
keys = np.arange(len(molecules))

index.add(keys, fingerprints)
matches = index.search(fingerprints, 10)

该方法被用于构建"USearch Molecules",这是最大的化学信息学数据集之一,包含70亿个小分子和280亿个指纹。

USearch + POI坐标 = GIS应用

类似于向量和分子搜索,USearch也可用于地理信息系统。 Haversine距离是现成可用的,但你也可以定义更复杂的关系,如考虑地球扁率的Vincenty公式。

from numba import cfunc, types, carray
import math

# 将维度定义为2,表示纬度和经度
ndim = 2

# 自定义度量的签名
signature = types.float32(
    types.CPointer(types.float32),
    types.CPointer(types.float32))

# WGS-84椭球参数
a = 6378137.0  # 长半轴(米)
f = 1 / 298.257223563  # 扁率
b = (1 - f) * a  # 短半轴

def vincenty_distance(a_ptr, b_ptr):
    a_array = carray(a_ptr, ndim)
    b_array = carray(b_ptr, ndim)
    lat1, lon1, lat2, lon2 = a_array[0], a_array[1], b_array[0], b_array[1]
    L, U1, U2 = lon2 - lon1, math.atan((1 - f) * math.tan(lat1)), math.atan((1 - f) * math.tan(lat2))
    sinU1, cosU1, sinU2, cosU2 = math.sin(U1), math.cos(U1), math.sin(U2), math.cos(U2)
    lambda_, iterLimit = L, 100
    while iterLimit > 0:
        iterLimit -= 1
        sinLambda, cosLambda = math.sin(lambda_), math.cos(lambda_)
        sinSigma = math.sqrt((cosU2 * sinLambda) ** 2 + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) ** 2)
        if sinSigma == 0: return 0.0  # 重合点
        cosSigma, sigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda, math.atan2(sinSigma, cosSigma)
        sinAlpha, cos2Alpha = cosU1 * cosU2 * sinLambda / sinSigma, 1 - (cosU1 * cosU2 * sinLambda / sinSigma) ** 2
        cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cos2Alpha if not math.isnan(cosSigma - 2 * sinU1 * sinU2 / cos2Alpha) else 0  # 赤道线
        C = f / 16 * cos2Alpha * (4 + f * (4 - 3 * cos2Alpha))
        lambda_, lambdaP = L + (1 - C) * f * (sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM ** 2)))), lambda_
        if abs(lambda_ - lambdaP) <= 1e-12: break
    if iterLimit == 0: return float('nan')  # 公式未收敛
    u2 = cos2Alpha * (a ** 2 - b ** 2) / (b ** 2)
    A = 1 + u2 / 16384 * (4096 + u2 * (-768 + u2 * (320 - 175 * u2)))
    B = u2 / 1024 * (256 + u2 * (-128 + u2 * (74 - 47 * u2)))
    deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM ** 2) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma ** 2) * (-3 + 4 * cos2SigmaM ** 2)))
    s = b * A * (sigma - deltaSigma)
    return s / 1000.0  # 距离(公里)

# 使用示例:
index = Index(ndim=ndim, metric=CompiledMetric(
    pointer=vincenty_distance.address,
    kind=MetricKind.Haversine,
    signature=MetricSignature.ArrayArray,
))

集成与用户

引用

@software{Vardanian_USearch_2023,
doi = {10.5281/zenodo.7949416},
author = {Vardanian, Ash},
title = {{USearch by Unum Cloud}},
url = {https://github.com/unum-cloud/usearch},
version = {2.13.4},
year = {2023},
month = oct,
}
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号