向量数据库简介

06-09-2025

更新 2025-06-20

  • 添加关于 ChromaDB/SQLLite 采样的章节。 更新:2025-06-19
  • 新增近似最近邻(ANN)算法相关内容。

向量数据库是一种存储和管理向量数据的数据库。向量数据是表示为向量的数据,例如空间中的点或时间序列中的向量。向量数据库在各种应用中使用,如图像和视频搜索、自然语言处理和推荐系统。在机器学习中,我们通常使用向量数据库来存储来自BERT或OpenAI等模型的嵌入文本数据;图像数据(来自CNN或CLIP的嵌入)以及音频/视频/基因组数据。与SQL的WHERE子句等传统精确匹配查询不同,向量数据库支持相似性搜索,例如”查找与自注意力论文最相似的10篇文档”。向量数据库用于涉及语义搜索、推荐系统、异常检测和检索增强生成(RAG)的应用。

向量数据库存在的意义在于它能够保留文本数据的语义信息,也就是说内容相似的数据会生成相似的向量(如余弦相似度)。

from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
embedding = model.encode("ChatGPT is somewhat intelligent.")

像BERT这样的模型会为文本生成向量嵌入。我们随后会建立索引(index),以支持快速近似最近邻(ANN)搜索。ANN是现代向量数据库的核心技术,实际上是一类相似性搜索算法的统称。

近似最近邻(ANN)算法简介

  • 倒排文件索引(IVF):IVF通过k-means将数据集聚类为k个粗粒度中心点(centroid),每个向量分配到最近的中心点。查询时,先只在与查询向量最接近的前n个中心点对应的簇中进行精确搜索(粗量化)。这种方法时间复杂度为Olog(k) + 局部小范围搜索,内存消耗小,常作为基线方法。

  • 图结构算法:如分层可导航小世界图(HNSW),构建多层图结构,上层稀疏有长距离连接,下层稠密有局部连接。查询时自顶向下贪心搜索,每层选择距离最近的邻居,逐层下沉。该算法极快,时间复杂度Olog(n),且准确率高。

  • 哈希算法:如局部敏感哈希(LSH),将高维向量投影到哈希桶中,相似向量以高概率落入同一桶。通常用多个哈希表提升准确率。时间复杂度O(1) + 小规模候选集精查,插入速度快,但在高维空间表现不佳。

常见的相似度计算方式包括L2欧氏距离、余弦相似度、内积、Jaccard/Hamming等。

以下是IVF+PQ的示例:

import faiss
import numpy as np

d = 128  # 向量维度
nb = 100000  # 向量数量
nlist = 100  # 分区数

# 生成训练数据
xb = np.random.random((nb, d)).astype('float32')

# 使用IVF+PQ建立索引
quantizer = faiss.IndexFlatL2(d)
index = faiss.IndexIVFPQ(quantizer, d, nlist, 16, 8)  # 16个子量化器,每个8位
index.train(xb)
index.add(xb)

# 查询
xq = np.random.random((1, d)).astype('float32')
index.nprobe = 10  # 查询时搜索的簇数
D, I = index.search(xq, 5)  # 返回前5个结果

向量数据库

ChromaDB 使用 SQLite 作为其后端,并创建多个表来管理集合、嵌入、元数据等。以下是对 ChromaDB SQLite 数据库中常见表的简要说明:

  • collections:存储每个集合(一组相关的嵌入/文档)的信息。
  • collection_metadata:存储与集合相关的元数据(键值对)。
  • embeddings:包含实际的向量嵌入及其关联文档的引用。
  • embedding_metadata:存储每个嵌入的元数据(如文档 ID、标签等)。
  • segments:用于管理数据分段,有助于高效存储和检索。
  • segment_metadata:每个分段的元数据。
  • embeddings_queue 和 embeddings_queue_config:用于管理队列中的嵌入操作,可能用于异步处理。
  • databases:存储多租户环境下不同逻辑数据库的信息。
  • maintenance_log:记录维护操作或后台任务。
  • migrations:跟踪模式迁移(数据库版本控制)。
  • embedding_fulltext_search 和相关表:支持对嵌入或文档进行全文搜索功能。

使用 SQLite CLI,我们可以方便地查看实际的 chromaDB:

命令 .schema TABLENAME 显示表的结构。在此示例中, 我们查看 embeddings 表。然后我们启用列标题,以便 SELECT 语句显示列标题和所选值的 对应值。


sqlite> .schema embeddings
CREATE TABLE embeddings (
    id INTEGER PRIMARY KEY,
    segment_id TEXT NOT NULL,
    embedding_id TEXT NOT NULL,
    seq_id BLOB NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE (segment_id, embedding_id)
);

sqlite> .headers on
sqlite> .mode column
sqlite> select * from embeddings limit 1;
id  segment_id                            embedding_id                          seq_id  created_at
--  ----------------------------------- -  ------------------------------------  ------  -------------------
1   33e29416-2f64-4d96-a0db-4d95ea626ee6  5d7365f3-286c-45d7-be70-0e0d24df12b3  1       2025-06-13 12:49:01

Milvus是一个开源的向量数据库,专为存储和检索嵌入向量而优化。它是一个分布式向量数据库,可以扩展以处理大量数据。它构建在Apache Arrow之上,并使用列式存储格式存储数据。它还提供gRPC和REST API,便于与其他应用程序集成。它用Go编写,可在Linux、Windows和macOS上使用。它能够使用近似最近邻(ANN)算法(如HNSW、IVF和ANNOY)处理大规模(数十亿向量)的相似性搜索。

Milvus lite是Milvus的轻量级、仅本地版本。它可以在内存中或文件系统上运行。它非常适合小型应用程序或测试目的。

典型操作

连接

from pymilvus import connections
connections.connect("default", host="localhost", port="19530")

定义模式和创建集合

from pymilvus import CollectionSchema, FieldSchema, DataType, Collection

fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=False),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=128)
]
schema = CollectionSchema(fields, description="我的向量集合")
collection = Collection(name="my_collection", schema=schema)

插入向量数据

import numpy as np

ids = [1, 2, 3]
vectors = np.random.rand(3, 128).tolist()

collection.insert([ids, vectors])

创建索引

index_params = {
    "index_type": "IVF_FLAT",
    "metric_type": "L2",
    "params": {"nlist": 128}
}
collection.create_index(field_name="embedding", index_params=index_params)

加载和搜索

collection.load()

search_params = {"metric_type": "L2", "params": {"nprobe": 10}}
query_vector = [np.random.rand(128).tolist()]
results = collection.search(query_vector, "embedding", search_params, limit=2)

for hit in results[0]:
    print(f"ID: {hit.id}, 距离: {hit.distance}")

混合搜索过滤

Milvus允许将向量搜索与结构化过滤器(例如WHERE id > 10)结合使用。如果模式支持,您可以在search()方法中包含一个过滤器。

在未来的博客中,我们将讨论向量数据库在RAG(Deepsearcher)应用中的具体用例。