第 8 章 · 01 vector_store:8 种向量库后端


第 8 章 · 01 vector_store:8 种向量库后端

本节摘要:本章装配管线第⑥段(polyglot 存储)的第一块基石——向量存储。semantica/vector_store/ 共 19 个文件、11263 行,用一个 VectorStore 门面统一了 8 种后端:本地 FAISS、内嵌 inmemory、轻量 SQLite-vec、复用 PostgreSQL 的 PgVector,以及云上四家 Qdrant/Weaviate/Milvus/Pinecone。本节拆解统一接口(add/search/delete/维度校验)如何在不同后端之间平滑分发,给出选型表,并演示"换后端=换一行参数"。

内容来源:原项目源码 semantica/vector_store/vector_store.pyfaiss_store.pypgvector_store.pysqlite_vec_store.pyqdrant_store.py__init__.py

⚠️ 注意:8 个后端里只有 inmemory 与 FAISS 是真正零外部服务的;pgvector 必须在 config 里给 connection_stringsqlite 必须给 db_path,缺了会在初始化时直接报错——不会静默降级到内存(未知名才会降级并打 warning)。

学习目标

阅读完本节,你应当能够:

  1. 背出 SUPPORTED_BACKENDS 里的 8 个后端名,并说出每个的部署形态(本地/自托管/云托管)。
  2. 解释 VectorStore.__init__ 如何做后端校验与分发,_init_backend_store 的 if/elif 链长什么样。
  3. 说出 store_vectorshasattr 探测 add/add_vectors 的适配技巧。
  4. 区分 FAISS 四种索引(Flat/IVF/HNSW/PQ)的取舍。
  5. 按场景选后端:开发、生产、已有 PG、本地实验各用什么。

一、八后端总览:一个集合变量定江山

先看门面类 VectorStore 的开头(vector_store.py:100-119):

100 class VectorStore: ... 112 SUPPORTED_BACKENDS = {"faiss", "weaviate", "qdrant", "milvus", "pinecone", "pgvector", "inmemory", "sqlite"} 114 def __init__(self, backend="faiss", config=None, max_workers=6, **kwargs): 115 if backend.lower() not in self.SUPPORTED_BACKENDS: 116 raise ValueError( 117 f"Unsupported backend: {backend}. " 118 f"Supported backends are: {...}" 119 )

一个 frozenset 语义的集合变量就是全部后端清单。8 个后端按部署形态分三档:

后端 文件 行数 形态 一句话定位
faiss faiss_store.py 551 本地库 单机向量检索事实标准,四种索引可玩
inmemory vector_store.py 内置 进程内 两个 dict,测试与最小示例专用
sqlite sqlite_vec_store.py 777 嵌入式 sqlite-vec 扩展,一个文件落盘的轻量持久化
pgvector pgvector_store.py 975 自托管 复用已有 PostgreSQL,不引入新组件
qdrant qdrant_store.py 650 自托管/云 payload 过滤好用,生产热门
milvus milvus_store.py 701 自托管/云 十亿级规模与分区能力
weaviate weaviate_store.py 712 自托管/云 schema 感知 + GraphQL 查询
pinecone pinecone_store.py 766 云托管 全托管免运维,按用量计费

注意 __init__.py 导出面(135-191 行):除 VectorStore 外还导出每个后端的 Client/Collection/Search 细粒度类(如 QdrantClient/QdrantCollection/QdrantSearch)——想绕过门面直连后端也留了门。同目录还住着第 6 章的老朋友 DecisionEmbeddingPipeline(921 行)与 decision_vector_methods.py:决策向量化就长在向量库里,门面还提供 store_decision(vector_store.py:875)直接把决策存成向量。

二、后端分发:一条 if/elif 链与它的容错

_init_backend_store(vector_store.py:165-269)是 8 后端的分发现场。以 pgvector 与 faiss 为例:

168 if self.backend == "pgvector": 180 if not connection_string: 180 raise ValueError( 181 "pgvector backend requires 'connection_string' in config. ...") 186 self._backend_store = PgVectorStore(...) 196 elif self.backend == "faiss": 198 self._backend_store = FAISSStore(...) ... 232 elif self.backend == "sqlite": 237 if not db_path: 238 raise ValueError( 239 "sqlite backend requires 'db_path' in config. ...") 246 self._backend_store = SQLiteVecStore(...) ... 258 else: # 未知名后端:降级 in-memory 并告警 259 self.logger.warning(f"Backend '{...}' not implemented, using in-memory") 260 self.backend = "inmemory"

三层容错值得留意:缺必填参数→ValueError(fail fast,不吞错);缺依赖包→ImportError(263 行提示安装对应 extras);未知名→降级 inmemory(带 warning)。inmemory 分支不走这条链(137 行 if self.backend != "inmemory" 才初始化后端),而是在 141-163 行直接建两个字典:

141 if self.backend == "inmemory": 142 self.vectors: Dict[str, np.ndarray] = {} 143 self.metadata: Dict[str, Dict[str, Any]] = {}

inmemory 就是"字典 + 余弦相似度暴力搜",VectorRetriever.search_similar(1350 行)里注释写明用带 epsilon 的余弦相似度避免除零。慢,但结果精确、零依赖——这正是第 1 章"无 key 跑通"承诺在存储层的落点。

三、统一接口:add/search/delete 与维度

SearchResult 的类型定义(vector_store.py:81-89)规定了所有后端必须对齐的返回形状:id/score/metadata/vector/distance,其中注释强调 score 在所有后端归一化到 0.0–1.0distance 保留后端原生距离值。这是"换后端不换业务代码"的契约核心。

写入路径 store_vectors(vector_store.py:490-529)展示了最有趣的适配层——各后端写入方法名不一致,用 hasattr 逐个探测:

507 if self._backend_store: 510 if hasattr(self._backend_store, 'add'): 511 return self._backend_store.add(vectors, metadata, **options) 512 elif hasattr(self._backend_store, 'add_vectors'): ... 519 params = inspect.signature( self._backend_store.add_vectors).parameters ... 529 raise NotImplementedError(f"Backend store {...} does not have " "add or add_vectors method")

三级探测:先 add(pgvector/sqlite-vec/qdrant 的新接口)→ 再 add_vectors(FAISS 等旧接口,519 行还用 inspect.signature 检查它是否接受 metadata 参数)→ 都没有就 NotImplementedError。删除路径同理(786-795 行探测 delete/delete_vectors)。维度契约则在写入前由后端自行校验(FAISS 建索引时固定 self.dimension,vector_store.py:127 默认 768)。

四、四种后端的实现性格

FAISS(faiss_store.py:193-236)——FAISSIndexBuilder.build_index 一个方法造四种索引:

215 index = faiss.IndexFlatL2(self.dimension) # flat:暴力精确 222 index = faiss.IndexIVFFlat(quantizer, ..., nlist) # ivf:k-means 倒排 226 index = faiss.IndexHNSWFlat(self.dimension, M) # hnsw:多层图 231 index = faiss.IndexPQ(self.dimension, m, bits) # pq:乘积量化压缩

flat 精确但要全扫;IVF 需先 train_index(238-246 行,只对 IVF 训练);HNSW 免训练、M=32 控图密度;PQ 换内存。索引可 save/load(118-133 行,faiss.write_index)。

PgVector(pgvector_store.py)——卖点是"不引入新组件":_get_connection(184-194 行)拿到连接后 register_vector(conn) 注册 vector 类型;_verify_pgvector_extension(210 行)确认 CREATE EXTENSION vector 已装;_ensure_table_exists(230 行)建表存向量列;create_index(769 行)支持 hnsw/ivfflat 索引。向量检索的运维复杂度=你已有的 PG

SQLite-vec(sqlite_vec_store.py)——依赖是可选的(52-58 行 SQLITE_VEC_AVAILABLE = find_spec("sqlite_vec") is not None),连接支持 :memory:(160 行)或文件路径,底层是 sqlite-vec 的 vec0 虚拟表(65 行)。一个 .db 文件就是一套可持久化的向量库——嵌入式场景(桌面应用、边缘设备)的最优解。

Qdrant(qdrant_store.py:137-156)——写入走 client.upsert、检索走 client.search,payload 过滤是它的招牌;pinecone/milvus/weaviate 同构,都是"客户端类 + 集合管理 + 检索类"三件套,差异被门面吸收。

五、后端选型表与一行切换

场景 推荐 理由
开发/单元测试 inmemory 零依赖、随起随灭、结果精确
桌面/边缘/单机原型 sqlite(或 faiss 一个文件落盘;FAISS 还能玩索引类型
中小生产、检索质量优先 qdrant payload 过滤 + 性能均衡
亿级规模、多租户分区 milvus 分区与水平扩展成熟
已有 PostgreSQL 基础设施 pgvector 复用运维/备份/权限,不添新件
不想管任何服务器 pinecone 全托管,代价是数据出域与按量计费

切换后端只动构造那一行,下游全链路无感知:

# 开发:内存起步,无 key 无服务 store = VectorStore(backend="inmemory", dimension=768) # 上生产:换 qdrant,业务代码一行不改 store = VectorStore(backend="qdrant", config={"url": "http://qdrant:6333"}, dimension=768) # 已有 PG:直接复用 store = VectorStore(backend="pgvector", config={ "connection_string": "postgresql://user:pw@host:5432/db", "table_name": "semantica_vectors"}, dimension=768)

这就是"polyglot"三个字的分量:多样性在后端层消化,统一性在门面层供给。第 3 章图谱落库、第 6 章决策向量化、第 9 章混合检索,全都只认 VectorStore 这张脸。

💡 装配要点:polyglot 向量层的三板斧——①一个集合变量 SUPPORTED_BACKENDS 做白名单校验(vector_store.py:112);②一条 if/elif 分发链加三层容错(参数缺失 fail fast、依赖缺失 ImportError、未知名降级 inmemory);③hasattr + inspect.signature 的鸭子类型适配,抹平各后端方法名差异。score 归一化到 0–1 是跨后端可比的隐藏契约。

本节要点回顾

  1. 8 后端:faiss/weaviate/qdrant/milvus/pinecone/pgvector/inmemory/sqlite(vector_store.py:112);三档形态——本地、自托管、云托管。
  2. 分发与容错_init_backend_store if/elif 链;pgvector 缺 connection_string、sqlite 缺 db_path 直接 ValueError;未知名降级 inmemory 并告警。
  3. 统一契约SearchResult 的 score 全后端归一化 0–1;store_vectors/delete_vectors 用 hasattr 探测 add/add_vectors 完成适配。
  4. 实现性格:FAISS 四索引(Flat/IVF/HNSW/PQ);pgvector 复用 PG(register_vector + hnsw 索引);sqlite-vec 零服务一个文件;qdrant 靠 payload 过滤。
  5. 选型:开发 inmemory→单机 sqlite/faiss→生产 qdrant/milvus→已有 PG 用 pgvector→免运维 pinecone;切换=换一行构造参数。
  6. 决策向量化同屋檐DecisionEmbeddingPipelinestore_decision 就住在 vector_store 里,向量库同时是第 6 章决策智能的底座。

下一节:01 节装好了向量这一维。02 节把另外两维也装上——4 种图数据库(Neo4j/FalkorDB/Apache AGE/Amazon Neptune)与 RDF 三元组库(Oxigraph/Blazegraph/Jena/RDF4J),属性图与语义网两大阵营在同一个抽象下共处。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U