← 返回 Semantica 专题首页 🌱 SEMANTICA · COOKBOOK · 入门系列

向量存储 - 全面指南

Semantica 官方 Cookbook 中文翻译 · 第 13 / 37 篇

📦 semantica 🕸️ 知识图谱 🔎 GraphRAG

1概览

本 notebook 对 Semantica 的 vector_store 模块进行了全面讲解,演示了向量存储、相似度检索、混合检索以及面向语义检索的多后端支持。

文档API Reference

学习目标

学完本 notebook 后,你将能够:

  • 存储和管理带元数据的向量
  • 使用不同度量执行相似度检索
  • 使用结合向量和元数据的混合检索
  • 使用多个向量存储后端(FAISS、Weaviate 等)
  • 创建和管理向量索引
  • 过滤和排序检索结果
  • 实现面向多租户的命名空间隔离

你将学到什么

组件 用途 何时使用
VectorStore 主要向量存储 所有向量操作
VectorIndexer 索引创建 性能优化
VectorRetriever 相似度检索 查找相似向量
HybridSearch 组合检索 向量 + 元数据过滤
MetadataFilter 元数据过滤 按属性过滤
MetadataStore 元数据管理 存储向量元数据
NamespaceManager 多租户 隔离向量集合

2安装

从 PyPI 安装 Semantica:

pip install semantica
# 或安装所有可选依赖:
pip install semantica[all]

# 安装 Semantica
!pip install -q semantica

3步骤 1:基础向量存储

让我们从用于基础向量存储和检索的 VectorStore 开始。

什么是 VectorStore?

VectorStore 是向量操作的主要接口: - 存储:存储带元数据的向量 - 检索:查找相似向量 - CRUD:创建、读取、更新、删除操作 - 多后端:支持 FAISS、Weaviate、Qdrant、Milvus

from semantica.vector_store import VectorStore
from semantica.embeddings import TextEmbedder
import numpy as np

# 1. 初始化 Embedder(选择提供方和模型)
# 你可以选择 'sentence_transformers' 或 'fastembed'
embedder = TextEmbedder(method="sentence_transformers", model_name="all-MiniLM-L6-v2")
dimension = embedder.get_embedding_dimension()

# 2. 创建向量存储
store = VectorStore(backend="faiss", dimension=dimension)

# 3. 生成真实嵌入
texts = [f"Document {i}" for i in range(100)]
vectors = embedder.embed_batch(texts)

metadata = [
    {"text": txt, "category": "science" if i % 2 == 0 else "technology", "year": 2020 + (i % 4)}
    for i, txt in enumerate(texts)
]
# 4. 存储向量
vector_ids = store.store_vectors(vectors, metadata=metadata)

print(f"Stored {len(vector_ids)} vectors")
print(f"First 3 IDs: {vector_ids[:3]}")

4步骤 2:相似度检索

使用不同的相似度度量检索相似向量。

相似度度量

  • 余弦相似度:最适合语义相似度
  • L2 距离:欧几里得距离
  • 点积:快速,需要归一化向量
from semantica.vector_store import VectorIndexer, FAISSStore 
import numpy as np 
# 我们使用数据集中的第一个向量作为示例查询
if 'query_vector' not in locals():
    if 'vectors' in locals() and len(vectors) > 0:
        query_vector = vectors[0]
    else:
        # 如果向量也缺失,则回退(安全检查)
        query_vector = np.random.rand(dimension).astype('float32')

# 创建索引器
indexer = VectorIndexer(backend="faiss", dimension=dimension) 

# 创建 HNSW 索引以进行快速近似检索
adapter = FAISSStore(dimension=dimension) 
index = adapter.create_index(index_type="hnsw", metric="L2", m=16) 

# 将向量添加到索引
vectors_array = np.array(vectors).astype('float32') 
# 修复:移除了 'index' 参数。适配器使用其内部的 self.index
adapter.add_vectors(vectors_array, ids=vector_ids) 

# 使用索引进行检索
query_array = np.array(query_vector).astype('float32') 
# 修复:直接在 'index' 对象上调用 search,而不是在适配器上
distances, indices = index.search(query_array.reshape(1, -1), k=10) 

print(f"Index search found {len(indices[0])} results") 
print(f"Distances: {distances[0][:5]}")

5步骤 3:向量索引

为大型数据集创建索引以加快检索。

索引类型(FAISS)

  • Flat:精确检索(暴力搜索)
  • IVF:倒排文件索引(近似)
  • HNSW:层级图(最佳平衡)
  • PQ:乘积量化(压缩)
from semantica.vector_store import VectorIndexer, FAISSStore

# 从向量获取维度以确保一致性
dimension = len(vectors[0]) if len(vectors) > 0 else 384

# 创建索引器
indexer = VectorIndexer(backend="faiss", dimension=dimension)

# 创建 HNSW 索引以进行快速近似检索
adapter = FAISSStore(dimension=dimension)
index = adapter.create_index(index_type="hnsw", metric="L2", m=16)

# 将向量添加到索引
vectors_array = np.array(vectors).astype('float32')
adapter.add_vectors(vectors_array, ids=vector_ids)

# 使用索引进行检索
query_array = query_vector.astype('float32')
distances, indices = index.search(query_array.reshape(1, -1), k=10)

print(f"Index search found {len(indices[0])} results")
print(f"Distances: {distances[0][:5]}")

6步骤 4:混合检索

将向量相似度与元数据过滤相结合。

混合检索的优势

  • 在向量检索之前按元数据过滤
  • 组合多个检索条件
  • 更精确的结果
from semantica.vector_store import HybridSearch, MetadataFilter 
import numpy as np

# 创建混合检索
hybrid_search = HybridSearch() 

# 创建元数据过滤器
filter = MetadataFilter() \
    .eq("category", "science") \
    .gt("year", 2021) 

# 执行混合检索
# 确保 vectors 和 metadata 可用
if 'vectors' not in locals() or 'metadata' not in locals() or 'vector_ids' not in locals():
    print("Warning: vectors, metadata, or vector_ids are missing. Please run previous cells.")
else:
    hybrid_results = hybrid_search.search( 
        query_vector, 
        vectors, 
        metadata, 
        vector_ids, 
        filter=filter, 
        k=10 
    ) 

    print(f"Hybrid search found {len(hybrid_results)} results") 
    print("\nFiltered results (science, year > 2021):") 
    for i, result in enumerate(hybrid_results[:5], 1): 
        meta = result.get('metadata', {}) 
        print(f"{i}. Category: {meta.get('category')}, Year: {meta.get('year')}, Score: {result['score']:.3f}")

7步骤 5:元数据管理

将元数据与向量分开存储和查询。

元数据操作

  • 为向量存储元数据
  • 按元数据条件查询
  • 更新元数据
  • 模式验证
from semantica.vector_store import MetadataStore, MetadataSchema

# 创建元数据存储
meta_store = MetadataStore()

# 存储元数据
for i, vec_id in enumerate(vector_ids[:10]):
    meta_store.store_metadata(vec_id, metadata[i])

# 查询元数据
matching_ids = meta_store.query_metadata(
    {"category": "science"},
    operator="AND"
)

print(f"Found {len(matching_ids)} vectors with category='science'")

# 定义用于验证的模式
schema = MetadataSchema({
    "text": {"type": str, "required": True},
    "category": {"type": str, "required": True},
    "year": {"type": int, "required": True}
})

# 验证元数据
is_valid = schema.validate(metadata[0])
print(f"\nMetadata validation: {is_valid}")

8步骤 6:结果排序与融合

组合并排序来自多次检索的结果。

排序策略

  • 倒数排名融合(RRF):组合排序列表
  • 加权平均:对来自不同来源的分数进行加权
from semantica.vector_store import SearchRanker

# 使用 RRF 策略创建排序器
ranker = SearchRanker(strategy="reciprocal_rank_fusion")

# 模拟多次检索结果
results1 = [
    {"id": "vec_1", "score": 0.9},
    {"id": "vec_2", "score": 0.8},
    {"id": "vec_3", "score": 0.7}
]

results2 = [
    {"id": "vec_2", "score": 0.85},
    {"id": "vec_4", "score": 0.75},
    {"id": "vec_1", "score": 0.7}
]

# 使用 RRF 融合结果
fused_results = ranker.rank([results1, results2], k=60)

print("Fused results using RRF:")
for i, result in enumerate(fused_results, 1):
    print(f"{i}. ID: {result['id']}, Fused Score: {result['score']:.3f}")

9步骤 7:命名空间管理

为多租户应用隔离向量。

命名空间特性

  • 租户隔离
  • 访问控制
  • 按命名空间操作
from semantica.vector_store import NamespaceManager

# 创建命名空间管理器
ns_manager = NamespaceManager()

# 为不同租户创建命名空间
ns1 = ns_manager.create_namespace("tenant1", "Tenant 1 vectors")
ns2 = ns_manager.create_namespace("tenant2", "Tenant 2 vectors")

# 将向量添加到命名空间
for i in range(5):
    ns_manager.add_vector_to_namespace(f"t1_vec_{i}", "tenant1")
    ns_manager.add_vector_to_namespace(f"t2_vec_{i}", "tenant2")

# 获取命名空间向量
tenant1_vectors = ns_manager.get_namespace_vectors("tenant1")
tenant2_vectors = ns_manager.get_namespace_vectors("tenant2")

print(f"Tenant 1: {len(tenant1_vectors)} vectors")
print(f"Tenant 2: {len(tenant2_vectors)} vectors")

# 设置访问控制
ns1.set_access_control("user1", ["read", "write"])
ns1.set_access_control("user2", ["read"])

print(f"\nUser1 can write: {ns1.has_permission('user1', 'write')}")
print(f"User2 can write: {ns1.has_permission('user2', 'write')}")

10步骤 8:多后端支持

使用不同的向量存储后端。

支持的后端

后端 类型 最适合
FAISS 本地 开发、小型数据集
Weaviate 自托管 模式感知存储
Qdrant 自托管 高性能
Milvus 云/自托管 大规模

11步骤 9:最佳实践

性能提示

  1. 归一化向量:对于余弦相似度,始终进行归一化
  2. 使用 HNSW:速度/准确性的最佳平衡
  3. 批量操作:分批处理(100-1000)
  4. 先过滤:在向量检索之前应用元数据过滤器

后端选择

  • 开发:FAISS(本地、快速)
  • 生产:Weaviate/Qdrant(可扩展、自托管)
  • 自托管:Qdrant 或 Milvus(可控、高性能)
  • 模式感知:Weaviate(丰富的元数据)

索引配置

  • 小型数据集(<10K):Flat 索引
  • 中型数据集(10K-1M):HNSW
  • 大型数据集(>1M):IVF + PQ

12小结

你学到了什么

在本 notebook 中,你学会了如何:

  • 使用 VectorStore 存储和检索向量
  • 创建索引以优化性能
  • 使用带元数据过滤的混合检索
  • 将元数据与向量分开管理
  • 排序和融合检索结果
  • 实现命名空间隔离
  • 使用便捷函数进行快速操作
  • 使用多个后端适配器
  • 应用生产环境的最佳实践

关键要点

  1. 多后端:为你的需求选择合适的后端
  2. 混合检索:将向量与元数据结合以提高精度
  3. 索引:使用合适的索引类型以提升性能
  4. 元数据:分离元数据管理以提高灵活性
  5. 命名空间:为多租户隔离向量

下一步

延伸阅读: - Vector Store API Reference - Advanced Vector Store Notebook - Embedding Generation


有问题或疑问? 查看我们的 GitHub repositorydocumentation