向量数据库选型:Chroma、Milvus、pgvector、ES对比与避坑

发布时间:2026/10/12 21:24:00
向量数据库选型:Chroma、Milvus、pgvector、ES对比与避坑 最近几个月我这边收到最多的技术问题之一就是“我要搭一个知识库或者做语义搜索向量数据库到底选哪个”也难怪大家一搜资料满屏都是Chroma、Milvus、pgvector、Elasticsearch这几个名字每一个都有教程每一个看起来都靠谱结果反而是越看越没底。我自己在过去一年里把这几样东西在不同项目里轮着用了一遍从本地小脚本到线上服务都碰过所以这篇不打算单纯翻译官方文档而是直接聊选型判断、核心原理和落地时的坑。如果你正在做RAG、知识库、相似文本/图片检索或者只是帮团队做技术预研这篇文章应该能帮你省下不少试错时间。先说一个可能反直觉的结论这四个方案并不是同一类东西硬比性能没有意义。选型之前先想清楚你要做的是“一个用完就扔的原型”还是“一台要长期跑在机房里的服务”。下面我会把这四个方案的原理、实操和避坑经验都完整过一遍。1. 先搞清楚这四样东西的本质区别1.1 一句话定位这四套方案我经常用一句话给团队新人快速建立概念Chroma是嵌入式向量库Milvus是独立的分布式向量数据库pgvector是PostgreSQL的向量插件Elasticsearch是带向量检索能力的搜索引擎。这几者的本质差异决定了它们的部署方式、扩缩容能力和运维成本。Chroma像你电脑里的SQLiteHNSW索引和检索逻辑都嵌在你的应用进程里Milvus则是一个完整的数据库系统有自己的集群角色、元数据服务和存储层pgvector不引入新服务但你需要有一个能承担向量检索压力的PostgreSQL实例Elasticsearch则是在倒排索引之外额外挂上了一棵向量索引树。如果这四样东西放到一个表里看会更直观方案本质一句话定位典型部署形态Chroma嵌入式向量库本地优先开发最方便Python进程内/单机文件Milvus分布式向量数据库海量向量、高并发场景的专业选手独立集群支持K8spgvectorPostgreSQL扩展业务和向量数据放一起随PostgreSQL一起部署Elasticsearch搜索引擎 向量在全文检索里加入语义召回独立ES集群这个差异不是嘴上说说它直接决定了你后面所有操作路径。比如你选了Milvus就要面对etcd、MinIO、查询节点、索引节点这些基础设施甚至有可能会问“为什么我的服务角色没起来”。而选了Chroma你只需要一个Python环境pip install之后就能跑。没有哪个方案是绝对正确的只有哪个更适合你当前的约束条件。1.2 选型不是比性能而是比场景见过很多人在群里争论“谁比谁快”其实脱离了场景谈性能基本没有意义。我一般会按这几个方向来引导需求。如果你的目标是三天内做一个本地知识库原型或者在LangChain里快速验证效果Chroma是最优先的选择。它开发成本极低文档也全你不需要为它单独部署任何服务。如果你们的业务数据本身就存在PostgreSQL里向量只是文章、商品、用户文档的一个附加属性那pgvector是天然的答案因为你能用SQL直接关联业务字段避免在两套系统之间做数据同步。如果你们的搜索团队已经维护着一套Elasticsearch现在只是想在原有搜索能力上增加语义召回那在ES上扩展dense_vector和kNN反而是成本最低的路径。而一旦你的数据规模预计到千万级以上或者查询QPS需要明显超出单机能力这时候才是Milvus真正发挥价值的地方。2. 逐个拆解四个方案的核心逻辑2.1 Chroma本地优先开发者的“瑞士军刀”Chroma是我做原型时用得最顺手的方案。它把“集合Collection”作为核心概念一个Collection里有文档、向量、元数据和ID用户可以按ID或元数据做过滤。底层索引用的是HNSW默认距离度量是余弦相似度。因为它是嵌入式设计数据默认持久化到本地目录所以非常适合个人知识库、教学示例和内部工具。LangChain和LlamaIndex里对Chroma的封装非常完善几十行代码就能把文档切片、embedding、写入、查询串起来。很多人误以为Chroma不能上生产其实它在数据量不太大、单机可承载的场景里完全能跑。只不过它没有内置分布式能力如果未来数据规模上来了或者需要高可用就得考虑迁移。我见过一些团队把Chroma直接跑在服务器上提供服务配合持久化目录稳定性还不错但需要自己处理备份和并发控制。需要注意的点是Chroma默认的embedding函数会在第一次使用时下载模型文件离线环境经常在这里卡住。正确的做法是提前在应用里统一生成好向量只把vector和metadata交给Chroma这样既绕开模型下载问题也方便以后切换embedding模型。2.2 Milvus为海量向量而生的分布式系统Milvus是一款真正的分布式向量数据库它从诞生起就盯着“海量向量、高并发检索”这个场景。它的架构里有协调节点、数据节点、索引节点和查询节点还会用消息队列和对象存储把数据链路串起来。即便单机模式也至少需要etcd、MinIO、standalone三个组件配合通过Docker Compose或者Kubernetes部署。生产环境里Milvus可以把查询节点和索引节点横向扩展甚至用GPU加速索引构建和检索。Milvus支持多种索引类型比如IVF_FLAT、IVF_PQ、HNSW、DiskANN等。其中DiskANN可以把索引放到磁盘上适合“索引太大放不进内存”的场景。这些索引各有参数调起来需要一定经验。如果你的业务场景是图片特征召回、短视频相似推荐、亿级知识库切片搜索那Milvus是这几个方案里最能扛事的选择。但代价是运维复杂度明显要高于其他三个组件多日志分散一旦集群异常排查链路也会比较长。我用Milvus的经验是本地验证和写demo没问题真正上线前一定要把监控、告警和备份恢复方案提前想好。否则等集群真出了问题你拿着几十个Pod日志会有点懵。不过话又说回来正是因为组件多它才能在一个更大的数据规模上做到可控。2.3 pgvector不离开业务数据库的“安静方案”pgvector不是另一个数据库而是PostgreSQL的一个扩展插件。它给数据库增加了一种vector(n)字段类型然后配套提供索引和距离运算。这是它最大的魅力——你的用户表、文章表、订单表本来就在PostgreSQL里现在只需要多一列存向量就可以用普通的SQL做向量最近邻搜索。业务事务和向量写入在同一个事务里提交不会有跨系统一致性的问题。pgvector支持L2距离、内积和余弦距离这三种度量索引方面有IVFFlat和HNSW两种。IVFFlat构建快、索引小但召回率受训练列表影响HNSW召回率高、查询快但占用内存更多。在百万级向量规模下pgvector完全可以胜任。实际项目中我经常把文章id、作者、标签这些都放在同一个表里元数据过滤直接用WHERE子句根本不需要再维护一套过滤系统查询非常直观。不过pgvector也有几个容易踩的坑。一是向量的维度在建表时就固定了比如vector(384)换embedding模型时只能重建列二是HNSW索引对内存不客气如果PostgreSQL的shared_buffers和maintenance_work_mem没调好建索引过程会变得非常漫长三是向量检索和OLTP业务共用同一个实例时要评估好资源隔离否则一个大查询可能把正常业务拖垮。2.4 Elasticsearch从全文搜索到混合检索Elasticsearch本来不是向量数据库但它在7.x引入了dense_vector字段类型8.x又补充了HNSW索引和原生kNN搜索所以现在可以完全在一个ES集群里做向量检索。更重要的是ES把关键词召回和向量召回放到了同一个框架里可以用RRFReciprocal Rank Fusion做混合排序。这个能力在做RAG时非常香因为很多业务查询本身包含明确术语比如“退款流程”这时候BM25能精准命中而向量召回能补充一些语义相似但关键词不重叠的内容。选择ES的前提通常是你们已经有ES在跑或者团队对ES运维很熟。常见的场景包括站内搜索、日志分析、商品检索升级。加入了向量字段之后每一个文档都会多出一个固定维度的浮点数组这意味着索引体积、磁盘占用和内存占用都会上涨。ES的JVM堆内存、分片数、段合并策略都会影响向量检索的表现。配置向量字段时要注意dense_vector的index参数是否开启。如果开启ES会为向量建立HNSW索引如果不开启只能用script_score做暴力计算数据量大时性能会很难看。所以不是加一个向量字段就算完事索引方式必须提前规划好。3. 选型拆解数据、查询、运维、成本四个维度3.1 数据规模从“千条”到“亿条”分水岭在哪我在选型时不会先问“哪个最快”而是问“你预计数据量会涨到多少”。这里给一个基于我经验的量级参考不是绝对精确但用来做初步判断足够了。数据量级优先考虑方案原因10万条以内Chroma开发效率高单机内存足够几十毫秒内返回10万到数百万pgvector / Elasticsearch可以靠单机或少量节点扛住数据库耦合更容易千万级以上或QPS很高Milvus需要横向扩展用独立向量库更稳这个分水岭不是固定的。如果数据量只有几百万但查询QPS非常高pgvector依然可能成为瓶颈因为向量检索要消耗大量CPU和内存。反之如果数据量到了千万但只是离线跑批任务对延迟不敏感ES也能硬扛。但是总体来看数据量和查询并发是两个最核心的限制条件先按它们画一个选择范围再谈细节。3.2 查询方式相似度度量、元数据过滤、混合检索很多人的需求并不是“纯向量搜索”而是“在某个分类下找相似内容”这就会牵涉到过滤逻辑。四个方案对元数据过滤的支持差别很大Chroma能用where做简单的等于/包含过滤但复杂条件支持有限pgvector使用原生SQL过滤能力最灵活Milvus有一套表达式过滤语法支持范围、IN、布尔组合Elasticsearch则用filter context和kNN结合。这里有一个非常容易被忽略的问题先过滤后检索还是先检索后过滤。向量索引和业务字段索引是两套独立的索引结构如果先按元数据过滤把候选集缩小之后再进向量索引HNSW图里可用的入口节点会变少召回质量可能下降。反过来如果只召回topK条再做过滤过滤条件严格时最后可能只剩一两条。我常用的做法是把召回数量扩大到最终期望数量的5到10倍再做应用侧过滤或精排。如果你用的系统支持filter和kNN深度融合要仔细读文档确认过滤发生在向量搜索的哪个阶段。3.3 业务耦合与一致性数据往哪儿放向量数据不应该是孤立存在的它总是和业务实体绑定。比如一篇文章有标题、正文、作者、发布时间还有一个对应的embedding向量。如果这些数据都在PostgreSQL里pgvector能保证同一个事务里同时写入文章和向量数据不会出现“文章有了向量没写”的情况。这对很多业务系统来说是很大的优势不需要额外的消息队列或补偿任务。Chroma、Milvus和Elasticsearch都是独立存储相当于多了一个和业务数据库同步的系统。以Chroma为例你需要自己在应用层写数据写入逻辑如果写入一半失败还要考虑如何重试。Milvus和ES同样需要设计好数据源同步方案比如通过CDC、消息队列或者定时批处理。不要小看这个问题很多项目上线后真正的麻烦不是检索性能而是两边数据对不上。3.4 运维成本从半夜救火的角度想如果团队只有两三个人没有专职DBA或运维那每引入一个独立中间件都是在给未来的自己增加值班负担。Chroma最简单基本等于一个库备份就是拷贝目录。pgvector则是把运维压力转交给了你已有的PostgreSQL问题不大但要注意向量索引资源占用。ES和Milvus都需要认真对待集群监控、版本升级、数据备份和故障恢复。我见过不少团队选型时盯着benchmark里最优的那个结果上线之后没人看得懂监控版本升级做了一周线上业务天天被拖累。所以我会强烈建议在选型阶段就把“未来一年谁负责维护它”这个问题放到桌面上。选一个更平滑的方案哪怕单次查询慢几毫秒长期来看都更划算。方案部署复杂度监控门槛备份恢复难度Chroma极低低低拷贝文件即可pgvector低中依赖PG经验中用PG备份机制Elasticsearch高高中快照恢复可用Milvus高高高组件多4. 实操对照四个系统从零跑通向量检索4.1 Chroma一个Python脚本搞定本地语义搜索本地搭Chroma非常简单先安装依赖pip install chromadb下面这段代码创建了一个持久化Collection写入两段文档并做了语义查询。注意我指定了PersistentClient的path参数这样数据不会只存在内存里。import chromadb from chromadb.utils import embedding_functions client chromadb.PersistentClient(path./chroma_data) collection client.get_or_create_collection( nameknowledge_base, embedding_functionembedding_functions.DefaultEmbeddingFunction() ) collection.add( documents[ Chroma 适合快速搭建本地知识库原型, Milvus 适合大规模向量检索场景, ], metadatas[ {category: database, level: 1}, {category: database, level: 2}, ], ids[doc_1, doc_2] ) result collection.query( query_texts[应该用哪个向量数据库做原型], n_results2, where{category: database} ) print(result[documents])第一次运行会下载Embedding模型这个步骤在国内网络环境里很看运气。更稳妥的做法是自行生成向量然后用add时传embeddings参数查询时用query_embeddings参数。Chroma本身更像一个向量存储和检索引擎它不一定需要内置模型。4.2 pgvector用SQL做最近邻搜索pgvector的安装取决于你的PostgreSQL分支通常可以通过CREATE EXTENSION启用。启用之后建立一个带向量字段的表CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE articles ( id bigserial PRIMARY KEY, content text, embedding vector(384) );插入数据时需要把文本先经过Embedding模型转成384维向量再把数组转成PG兼容的字符串格式插入。比如在Python里你可以用str(vector.tolist())生成类似[0.01,0.02,...]的字符串。插入语句大致是INSERT INTO articles (content, embedding) VALUES (pgvector 让 Postgres 拥有向量检索能力, [0.01, 0.02, ...]);给向量字段创建HNSW索引CREATE INDEX ON articles USING hnsw (embedding vector_cosine_ops);查询最近的5条记录SELECT id, content, embedding [0.01, 0.02, ...] AS distance FROM articles ORDER BY embedding [0.01, 0.02, ...] LIMIT 5;这里是余弦距离-是欧氏距离#是负内积使用前要确认和你的模型匹配。如果召回结果差可以先用SET hnsw.ef_search 100;调大查询时的搜索宽度再观察效果。4.3 MilvusDocker Compose 单机部署与 Python 客户端Milvus单机部署最省事的方式是使用官方Docker Compose文件。安装Docker后在任意目录里执行wget https://github.com/milvus-io/milvus/releases/download/v2.4.15/milvus-standalone-docker-compose.yml -O docker-compose.yml docker compose up -dWindows环境要特别注意Docker Desktop的资源配置Milvus的etcd、MinIO和standalone三个容器一起跑内存占用不小建议给Docker分配4GB以上内存。启动完成后用Python连接pip install pymilvusfrom pymilvus import MilvusClient client MilvusClient(urihttp://localhost:19530) client.create_collection( collection_nameknowledge, dimension384, metric_typeCOSINE, ) client.insert( collection_nameknowledge, data[ {id: 1, vector: [0.1, 0.2, ...], text: 知识库切片内容}, {id: 2, vector: [0.3, 0.4, ...], text: 另一段内容}, ] ) res client.search( collection_nameknowledge, data[[0.1, 0.2, ...]], limit2, output_fields[text], ) print(res)这里必须提醒一点pymilvus版本之间的API差异很大旧文档里的connect()、insert()用法在2.3之后变化明显。你如果照着老教程写可能会遇到方法不存在或参数报错。建议以官方最新文档为准并且锁好版本号。4.4 Elasticsearch用kNN和混合检索改写传统搜索ES的向量检索在8.x版本里已经比较成熟核心是先定义一个dense_vector字段。下面这个Mapping创建了一个384维的向量字段并开启了HNSW索引PUT /my_index { mappings: { properties: { content: {type: text}, content_embedding: { type: dense_vector, dims: 384, index: true, similarity: cosine } } } }写入文档PUT /my_index/_doc/1 { content: Elasticsearch 的向量检索, content_embedding: [0.1, 0.2, 0.3, ...] }使用kNN查询GET /my_index/_search { knn: { field: content_embedding, query_vector: [0.1, 0.2, 0.3, ...], k: 10, num_candidates: 100 }, _source: [content] }你也可以把kNN和match查询组合起来做真正的混合搜索。num_candidates是控制召回候选池大小的参数默认值偏保守如果发现召回不理想可以逐步加大到200甚至300但会增加协调节点的开销。ES启动时如果只给了默认1GB堆内存大概率会在写入向量数据后频繁GC建议本地测试至少设置2到4GB。5. 实战中高频踩坑的排查清单5.1 召回率低先查索引参数和距离度量很多人在向量检索效果差的时候第一反应是换Embedding模型。但很多时候问题出在索引参数和距离度量上。HNSW索引有两个关键参数M控制每个节点的连接数efConstruction控制构建时的搜索宽度。M越大图的连通性越好但内存也越高efConstruction越大索引质量越高构建时间越长。查询时还有一个ef_search参数决定搜索时检查多少候选节点。如果效果不满意建议先把ef_search调大观察召回率变化再决定要不要重建索引。另外距离度量要选对。Cosine距离在向量未归一化时和L2距离的结果排序可能有很大差别。很多开源Embedding模型输出时本身就是归一化向量用L2和cosine可能差异不大但如果你在中间又做了拼接或加权平均最好显式归一化一次。5.2 元数据过滤先过滤还是后过滤我前面提过过滤和kNN结合的问题这里说一个真实案例。有个项目需要“在某个分类下推荐相似商品”商品总共十万条某个分类只有两百条。当时直接在向量搜索后用分类过滤结果经常出现剩下不到5条结果。后来改成先按分类过滤再对这两百条做精确距离计算速度反而更快效果也更稳。如果你的过滤条件筛选出的候选集非常小那么向量索引反而帮不上忙直接用暴力距离计算更合适。如果你的候选集很大比如几十万条还是需要走向量索引但要通过提高召回数量来弥补过滤损失。所以设计时不要把“过滤”只当成查询里的一个WHERE条件它会影响整个检索策略。5.3 写入慢、查询慢别急着加机器先看指标很多人遇到ES或Milvus写入慢第一反应是“加节点”。但很多问题出自更基础的地方磁盘IO、内存、段合并、批量大小。向量数据是浮点数组写入时比普通文本要复杂磁盘一旦接近饱和写入性能会肉眼可见地下降。判断磁盘是否有问题可以先看系统IO等待指标再查数据库的刷盘频率和段合并统计。ES可以打开慢查询日志pgvector可以用EXPLAIN ANALYZE看查询计划Milvus的监控面板里也有查询延迟和索引命中率。批量写入时不要一条一条插尝试每次批量500到1000条往往能明显提升吞吐。如果查询慢优先检查是否有大量请求打到暴力计算路径上。比如ES里dense_vector没有开启index: true或者pgvector建的索引没有被查询计划使用都会导致性能崩塌。先用EXPLAIN看索引是否生效再考虑加机器。5.4 维度冻结和模型更换一个容易忽略的隐性坑向量维度这件事在系统设计初期特别容易被忽略。Chroma一个Collection第一次写入后就会锁定维度Milvus建Collection时dimension必填pgvector的列类型自带维度ES的mapping里也写死了dims。这意味着你后期换Embedding模型时必须新建Collection或表再重新写入全部向量数据。我的习惯是在集合命名的阶段就把模型版本带进去比如wiki_2024_minilm_v2。这样切换模型时可以并行重建新集合对外提供只读查询等数据追平后再切流量。这个习惯能大幅降低线上切换的难度比临时改Schema优雅得多。6. 我现在的选择习惯和可复用经验6.1 我的默认选择顺序如果现在有人问我这四个方案怎么选我内心的排序大概是数据量100万以内、技术栈里已经有PostgreSQL的直接选pgvector因为它和业务数据的配合太好了如果只是快速做原型Chroma是最舒服的起点如果公司已经有ES集群并且要兼顾关键词搜索和语义搜索ES的混合检索是值得投入的方向只有当数据规模大概率冲上千万、或者需要独立的高并发向量服务时我才会一开始就上Milvus。这个顺序不是一成不变的。我见过一个知识库项目数据量只有几十万但因为公司对这个知识库的QPS预期很高最终选了Milvus因为ES集群资源不够pgvector也不好单独扩容。选型最终还是看约束条件。6.2 一个真正有用的验证方法我自己的习惯是在实际选型前不只看文档而是找一批最有代表性的真实数据大概1000到5000条就够然后分别用候选方案跑一遍。测试用的查询语句也要真实比如做客服知识库就把客户真正会问的问题拿去搜看前几名结果能不能直接用。再记录一下单次查询耗时和写入耗时。这个验证过程比看任何benchmark都有用因为你会很快发现有的方案在测试数据上“什么都好”但一加入元数据过滤就性能骤降有的方案安装部署特别顺利但写入一批真实文本后内存涨得飞快。我踩过几次坑之后现在几乎都会先跑这么一轮“最小可行验证”再拍板。毕竟选型这种事改起来比一开始多花十分钟的成本要高得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询