1概览
本 notebook 对 Semantica 的 vector_store 模块进行了全面讲解,演示了向量存储、相似度检索、混合检索以及面向语义检索的多后端支持。
学习目标
学完本 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:最佳实践
性能提示
- 归一化向量:对于余弦相似度,始终进行归一化
- 使用 HNSW:速度/准确性的最佳平衡
- 批量操作:分批处理(100-1000)
- 先过滤:在向量检索之前应用元数据过滤器
后端选择
- 开发:FAISS(本地、快速)
- 生产:Weaviate/Qdrant(可扩展、自托管)
- 自托管:Qdrant 或 Milvus(可控、高性能)
- 模式感知:Weaviate(丰富的元数据)
索引配置
- 小型数据集(<10K):Flat 索引
- 中型数据集(10K-1M):HNSW
- 大型数据集(>1M):IVF + PQ
12小结
你学到了什么
在本 notebook 中,你学会了如何:
- 使用 VectorStore 存储和检索向量
- 创建索引以优化性能
- 使用带元数据过滤的混合检索
- 将元数据与向量分开管理
- 排序和融合检索结果
- 实现命名空间隔离
- 使用便捷函数进行快速操作
- 使用多个后端适配器
- 应用生产环境的最佳实践
关键要点
- 多后端:为你的需求选择合适的后端
- 混合检索:将向量与元数据结合以提高精度
- 索引:使用合适的索引类型以提升性能
- 元数据:分离元数据管理以提高灵活性
- 命名空间:为多租户隔离向量
下一步
延伸阅读: - Vector Store API Reference - Advanced Vector Store Notebook - Embedding Generation
有问题或疑问? 查看我们的 GitHub repository 或 documentation。