mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
477 字
1 分钟
向量数据库深度解析
2025-07-29

一、向量数据库概述#

1.1 为什么需要向量数据库#

flowchart TB subgraph Traditional[" 传统数据库"] direction TB T1[" 结构化数据<br/>表格/关系"] T2[" 精确匹配<br/>SQL = WHERE"] T3[" 固定 Schema<br/>预定义字段"] T4[" 局限性<br/>无法理解语义"] end subgraph Vector[" 向量数据库"] direction TB V1[" 高维向量<br/>Embedding"] V2[" 相似性搜索<br/>KNN/ANN"] V3[" 灵活 Schema<br/>动态元数据"] V4[" 优势<br/>语义理解能力"] end Traditional -->|"演进"| Vector style Traditional fill:#ffe6e6,stroke:#ff6666 style Vector fill:#e6ffe6,stroke:#66cc66
graph TB subgraph "传统数据库局限" A["结构化数据"] B["精确匹配"] C["SQL 查询"] end subgraph "向量数据库优势" D["非结构化数据"] E["相似性搜索"] F["语义理解"] end A --> D B --> E C --> F
维度传统数据库向量数据库
数据类型结构化高维向量
查询方式精确匹配相似性搜索
应用场景业务数据AI 语义检索
召回率100%可调节(召回 vs 速度)

1.2 核心应用场景#

flowchart TB subgraph ImageSearch[" 图像检索"] direction LR I1["用户上传图片"] --> I2["CNN 提取特征"] I2 --> I3["特征向量"] I3 --> I4["向量检索"] I4 --> I5["相似图片"] end subgraph VoiceSearch[" 语音搜索"] direction LR V1["语音输入"] --> V2["ASR 转文本"] V2 --> V3["Embedding"] V3 --> V4["向量检索"] V4 --> V5["搜索结果"] end subgraph RAGSearch[" RAG 知识库"] direction LR R1["用户问题"] --> R2["问题向量化"] R2 --> R3["知识库检索"] R3 --> R4["相关文档"] R4 --> R5["LLM 生成答案"] end style ImageSearch fill:#e3f2fd style VoiceSearch fill:#fff8e1 style RAGSearch fill:#e8f5e9
graph LR A["用户上传图片"] --> B["提取特征向量"] B --> C["向量数据库检索"] C --> D["返回相似图片"] E["语音输入"] --> F["ASR 转文本"] F --> G["Embedding 向量化"] G --> H["向量检索"] H --> I["语音搜索结果"]

二、主流向量数据库对比#

2.0 架构对比概览#

flowchart TB subgraph MilvusArch[" Milvus 架构"] direction TB M1["SDK/API"] --> M2["Proxy"] M2 --> M3["Coordinator<br/>协调器集群"] M3 --> M4["Worker Nodes<br/>查询/索引/数据节点"] M4 --> M5["Object Storage<br/>MinIO/S3"] style MilvusArch fill:#e3f2fd end subgraph QdrantArch[" Qdrant 架构"] direction TB Q1["REST/gRPC API"] --> Q2["Collection Manager"] Q2 --> Q3["HNSW Index<br/>Rust 实现"] Q3 --> Q4["Storage<br/>RocksDB/内存"] style QdrantArch fill:#fff8e1 end subgraph PineconeArch[" Pinecone 架构"] direction TB P1["Client SDK"] --> P2["Pinecone Cloud"] P2 --> P3["Managed Index<br/>全托管"] P3 --> P4["Auto Scaling<br/>自动扩缩"] style PineconeArch fill:#e8f5e9 end subgraph ChromaArch[" Chroma 架构"] direction TB C1["Python SDK"] --> C2["DuckDB<br/>嵌入式存储"] C2 --> C3["HNSW Index<br/>hnswlib"] style ChromaArch fill:#fce4ec end

2.1 功能对比#

特性MilvusQdrantPineconeChromaWeaviate
部署方式自托管自托管云服务嵌入式自托管
索引算法HNSW/IVFHNSWHNSWHNSWHNSW
混合搜索
全文搜索
分布式
元数据过滤
Python SDK
Rust 核心

2.2 性能对比#

# 向量数据库性能基准测试框架
class VectorDBBenchmark:
def __init__(self, db_type: str):
self.db_type = db_type
def benchmark(self, dataset_size: int = 1000000):
"""QPS 与召回率基准测试"""
results = {
"milvus": {"qps": 5000, "recall": 0.95, "p99_latency": "15ms"},
"qdrant": {"qps": 8000, "recall": 0.97, "p99_latency": "8ms"},
"weaviate": {"qps": 3000, "recall": 0.93, "p99_latency": "20ms"},
}
return results.get(self.db_type, {})

三、索引算法详解#

3.1 HNSW 算法原理#

flowchart TB subgraph L2[" Layer 2 - 快速跳转"] direction LR A2["A"] --- B2["B"] B2 --- C2["C"] end subgraph L1[" Layer 1 - 中间过渡"] direction LR A1["A"] --- B1["D"] B1 --- C1["E"] D1["D"] --- E1["F"] end subgraph L0[" Layer 0 - 精确搜索"] direction LR A0["A"] --- B0["G"] B0 --- C0["H"] C0 --- D0["I"] D0 --- E0["J"] E0 --- F0["K"] F0 --- G0["L"] end L2 -.->|"下沉"| L1 L1 -.->|"下沉"| L0 Search[" 搜索过程:<br/>顶层入口 → 贪心搜索 → 逐层下沉"] style L2 fill:#e3f2fd,stroke:#1976d2 style L1 fill:#fff8e1,stroke:#f57c00 style L0 fill:#e8f5e9,stroke:#388e3c style Search fill:#f3e5f5
graph TB subgraph "Layer 2" A2["Node A"] B2["Node B"] C2["Node C"] end subgraph "Layer 1" A1["Node A"] --> B1["Node D"] B1 --> C1["Node E"] D1 --> E1["Node F"] end subgraph "Layer 0" A0["Node A"] --> B0["Node G"] B0 --> C0["Node H"] C0 --> D0["Node I"] D0 --> E0["Node J"] end
# HNSW 搜索算法伪代码
class HNSWIndex:
def __init__(self, m: int = 16, ef_construction: int = 200):
self.m = m # 每一层最多连接数
self.ef_construction = ef_construction # 构建时动态列表大小
def search(self, query_vector: list, ef: int = 100):
"""
搜索过程:
1. 从顶层开始,找到最近邻
2. 逐层向下,更新候选集
3. 最终在底层返回精确结果
"""
candidates = self._search_layer_0(query_vector, ef)
# 层间跳转
for layer in range(self.max_layer, 0, -1):
candidates = self._expand_neighbors(
candidates,
query_vector,
ef=ef_construction
)
return candidates[:ef]

3.2 IVF 倒排索引#

# IVF 索引原理
class IVFIndex:
def __init__(self, nlist: int = 1024):
self.nlist = nlist # 聚类中心数量
def build(self, vectors: list):
"""1. k-means 聚类建立倒排表"""
self.centers, assignments = kmeans(vectors, self.nlist)
# 2. 建立倒排表
self.inverted_index = {}
for i, cluster_id in enumerate(assignments):
if cluster_id not in self.inverted_index:
self.inverted_index[cluster_id] = []
self.inverted_index[cluster_id].append(i)
def search(self, query: list, nprobe: int = 10):
"""搜索时只扫描 nprobe 个聚类中心"""
# 1. 找到最近的 nprobe 个聚类中心
nearest_centers = self._find_nearest_centers(
query,
nprobe
)
# 2. 在这些聚类中暴力搜索
candidates = []
for center_id in nearest_centers:
candidates.extend(self.inverted_index[center_id])
return self._brute_force_search(query, candidates)

3.3 PQ 量化压缩#

# Product Quantization 原理
class PQIndex:
def __init__(self, m: int = 8, ks: int = 256):
"""
m: 分段数(通常 8-16)
ks: 每个子空间码本大小(通常 256)
"""
self.m = m
self.ks = ks
self.codebooks = []
def train(self, vectors: list):
"""训练码书"""
dim = len(vectors[0])
sub_dim = dim // self.m
for i in range(self.m):
# 对第 i 个子空间进行 k-means
sub_vectors = vectors[:, i*sub_dim:(i+1)*sub_dim]
codebook = kmeans(sub_vectors, self.ks)
self.codebooks.append(codebook)
def encode(self, vector: list):
"""编码:每个子空间找最近码字"""
codes = []
for i, codebook in enumerate(self.codebooks):
sub_vec = vector[i*self.sub_dim:(i+1)*self.sub_dim]
code = np.argmin(np.linalg.norm(codebook - sub_vec, axis=1))
codes.append(code)
return codes
def search(self, query: list, candidates: list):
"""距离计算使用查表而非暴力计算"""
# 预计算查询向量各子空间到各码字距离
distance_table = self._build_distance_table(query)
# 查表累加获取最终距离
for vector_id in candidates:
total_dist = sum(
distance_table[i][self.codes[vector_id][i]]
for i in range(self.m)
)

四、Milvus 深度解析#

4.0 Milvus 架构详解#

flowchart TB subgraph Client[" 客户端"] SDK["SDK<br/>Python/Go/Java/Node"] end subgraph Access[" 接入层"] direction LR P1["Proxy 1"] P2["Proxy 2"] P3["Proxy N"] P1 --- P2 --- P3 end subgraph Coordinator[" 协调层"] direction TB RC["Root Coordinator<br/>元数据管理"] QC["Query Coordinator<br/>查询调度"] DC["Data Coordinator<br/>数据管理"] IC["Index Coordinator<br/>索引管理"] end subgraph Worker[" 工作节点"] direction TB QN["Query Node<br/>查询执行"] DN["Data Node<br/>数据写入"] IN["Index Node<br/>索引构建"] end subgraph Storage[" 存储层"] direction TB MS["Message Storage<br/>Kafka/Pulsar"] OS["Object Storage<br/>MinIO/S3"] MD["Meta Storage<br/>etcd"] end SDK --> Access Access --> Coordinator Coordinator --> Worker Worker --> Storage style Client fill:#e8eaf6 style Access fill:#e3f2fd style Coordinator fill:#fff8e1 style Worker fill:#f3e5f5 style Storage fill:#e8f5e9

4.1 架构设计#

graph TB subgraph "接入层" A["SDK"] --> B["Proxy"] B --> C["RBAC"] end subgraph "协调层" C --> D["Root Coordinator"] C --> E["Query Coordinator"] C --> F["Index Coordinator"] end subgraph "执行层" D --> G["Query Node"] E --> H["Index Node"] F --> I["Data Node"] end subgraph "存储层" G --> J["Object Storage"] H --> J I --> J J --> K["MinIO/S3"] end

4.2 Milvus 使用示例#

from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType
# 1. 连接 Milvus
connections.connect(host='localhost', port='19530')
# 2. 定义 Schema
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768),
FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=100),
]
schema = CollectionSchema(fields=fields, description="向量检索集合")
# 3. 创建 Collection
collection = Collection(name="documents", schema=schema)
# 4. 创建索引
index_params = {
"index_type": "HNSW",
"params": {"M": 16, "efConstruction": 200},
"metric_type": "L2"
}
collection.create_index(field_name="embedding", index_params=index_params)
# 5. 插入数据
entities = [
[1, 2, 3], # id
[[0.1]*768, [0.2]*768], # embeddings
["科技", "娱乐"] # category
]
collection.insert(entities)
# 6. 搜索
search_params = {"metric_type": "L2", "params": {"ef": 100}}
results = collection.search(
data=[[0.1]*768],
anns_field="embedding",
param=search_params,
limit=10,
expr="category == '科技'"
)

五、Qdrant 深度解析#

5.0 Qdrant 架构详解#

flowchart TB subgraph Client[" 客户端"] direction LR C1["Python SDK"] C2["Rust SDK"] C3["REST API"] end subgraph API[" API 层"] direction TB REST["REST API<br/>HTTP/gRPC"] end subgraph Core[" 核心引擎 - Rust"] direction TB CM["Collection Manager<br/>集合管理"] SEG["Segment<br/>数据分片"] HNSW["HNSW Index<br/>高性能图索引"] QC["Quantization<br/>向量量化"] end subgraph Storage[" 存储层"] direction TB MEM["Memory<br/>热数据"] ROCK["RocksDB<br/>持久化存储"] SNAP["Snapshot<br/>备份恢复"] end Client --> API API --> Core Core --> Storage style Client fill:#e8eaf6 style API fill:#e3f2fd style Core fill:#fff8e1 style Storage fill:#e8f5e9
flowchart LR subgraph QdrantFeatures[" Qdrant 特色"] direction TB F1[" Rust 实现<br/>内存安全+高性能"] F2[" 单二进制部署<br/>运维简单"] F3[" 原生过滤<br/>元数据+向量联合"] F4[" 动态负载<br/>自动均衡"] end style QdrantFeatures fill:#f3e5f5

5.1 核心特性#

# Qdrant 配置文件
storage:
# 存储路径
storage_path: /qdrant/storage
# HNSW 参数
hnsw_index:
m: 16 # 连接数
ef_construct: 100 # 构建时搜索深度
full_scan_threshold: 10000 # 小于此规模用暴力搜索
# 量化配置
quantization:
binary: false
product:
compression: 8 # 压缩比

5.2 Qdrant 使用示例#

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, Filter
client = QdrantClient(host="localhost", port=6333)
# 1. 创建 Collection
client.create_collection(
collection_name="articles",
vectors_config=VectorParams(size=768, distance=Distance.COSINE)
)
# 2. 插入向量
client.upsert(
collection_name="articles",
points=[
{
"id": 1,
"vector": [0.1]*768,
"payload": {"title": "Python 教程", "category": "编程"}
},
]
)
# 3. 搜索
results = client.search(
collection_name="articles",
query_vector=[0.1]*768,
query_filter=Filter(
must=[
{"key": "category", "match": {"value": "编程"}}
]
),
limit=5
)
# 4. 范围搜索(按分数过滤)
results = client.search(
collection_name="articles",
query_vector=[0.1]*768,
score_threshold=0.8, # 只返回相似度 > 0.8 的结果
limit=10
)

六、选型指南#

6.0 四大数据库对比#

flowchart TB subgraph Milvus[" Milvus"] direction TB M_Pros["分布式架构<br/>超大规模支持<br/>功能最全面"] M_Cons["部署复杂<br/>运维成本高"] M_Use[" 适用: 大型企业<br/>亿级向量"] end subgraph Qdrant[" Qdrant"] direction TB Q_Pros["性能优异<br/>部署简单<br/>原生过滤"] Q_Cons["社区较小<br/>云服务起步"] Q_Use[" 适用: 高性能需求<br/>百万-千万级"] end subgraph Pinecone[" Pinecone"] direction TB P_Pros["全托管<br/>零运维<br/>快速上手"] P_Cons["成本较高<br/>数据主权问题"] P_Use[" 适用: 快速迭代<br/>SaaS 产品"] end subgraph Chroma[" Chroma"] direction TB C_Pros["嵌入式<br/>一行代码启动<br/>开源免费"] C_Cons["不支持分布式<br/>性能有限"] C_Use[" 适用: 原型开发<br/>小规模场景"] end style Milvus fill:#e3f2fd style Qdrant fill:#fff8e1 style Pinecone fill:#e8f5e9 style Chroma fill:#fce4ec

6.1 场景化选型#

场景推荐方案原因
快速原型Chroma嵌入式,一行代码启动
生产环境自托管Qdrant/Milvus性能好,功能完整
云原生 SaaSPinecone全托管,免运维
需要混合检索Qdrant/Weaviate支持向量+全文联合检索
超大规模(>1亿)Milvus分布式架构成熟
低延迟实时系统QdrantRust 实现,性能优异

6.2 性能优化建议#

# 向量数据库性能优化清单
optimization_checklist = {
"索引参数": {
"HNSW_M": "16-64,越大越精确但越慢",
"HNSW_ef": "100-500,搜索时动态调整",
"HNSW_ef_construction": "200-400,构建时精度"
},
"量化策略": {
"binary": "内存减半,速度加倍,精度略降",
"product": "内存压缩 4-16 倍,精度可调",
"scalar": "不影响精度,略微提升速度"
},
"硬件配置": {
"内存": "能装下全部向量 + 索引 > 80% 命中率",
"CPU": "影响索引构建速度,HNSW 构建 CPU 密集",
"SSD": "向量量大时必须,内存不足时代替"
}
}

七、总结#

mindmap root((向量数据库)) Milvus 分布式架构 云原生设计 功能最全 适用大规模 Qdrant Rust 高性能 单机部署简单 原生过滤强大 适用高并发 Pinecone 全托管 SaaS 零运维 快速上线 适用初创 Chroma 嵌入式轻量 开发便捷 原型首选 适用小规模 选型因素 数据规模 性能需求 运维能力 成本预算
数据库优势适用场景
Milvus功能全面,分布式成熟超大规模生产环境
Qdrant性能优异,Rust 实现高并发低延迟需求
Pinecone全托管,运维简单云原生,快速上线
Chroma轻量级,原型快速小规模,本地开发
Weaviate混合搜索,原生 GraphQL知识图谱+向量融合
flowchart TB Start[" 开始选型"] --> Q1{"数据规模?"} Q1 -->|"≤ 100 万"| Q2{"是否需要<br/>全文搜索?"} Q1 -->|"100 万 - 1 亿"| Q3{"性能优先<br/>还是功能优先?"} Q1 -->|"≥ 1 亿"| Milvus[" Milvus<br/>分布式架构"] Q2 -->|"是"| Weaviate[" Weaviate"] Q2 -->|"否"| Q4{"开发阶段?"} Q4 -->|"原型/开发"| Chroma[" Chroma"] Q4 -->|"生产环境"| Qdrant[" Qdrant"] Q3 -->|"性能优先"| Qdrant Q3 -->|"功能优先"| Milvus Q5{"运维能力?"} -->|"强"| Qdrant Q5 -->|"弱"| Pinecone[" Pinecone"] style Start fill:#e8eaf6 style Milvus fill:#e3f2fd style Qdrant fill:#fff8e1 style Pinecone fill:#e8f5e9 style Chroma fill:#fce4ec ```

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

向量数据库深度解析
https://blog.souloss.com/posts/ai-engineering/vector-database/
作者
Souloss
发布于
2025-07-29
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时