ES v.s Milvus v.s PG
需求
对比三种常见系统在向量搜索和全文搜索方面的性能与功能差异:ES(内置 Lucene、提供 k-NN 插件)、Milvus(专用向量数据库)和PostgreSQL(pgvector扩展)。它们各自优势不同:Milvus 设计用于亿级向量数据的高效检索;ES 是分布式全文搜索引擎,也可通过 k-NN 插件进行高维向量近似检索;pgvector 则将向量嵌入与关系数据共存,适用于混合查询场景。
测试环境与数据集
- 数据库版本:ES 8.17.4(docker部署,单节点)、Milvus 2.5.10(docker compose部署,standalone模式)、PostgreSQL 17.4-1+pgvector 0.7.0(Windows部署)。
- 向量数据集:统一采用 768 维嵌入(常见 BERT/CLIP 维度)。例如,MSMARCO/BERT模型输出768维句向量,LAION图像嵌入也为 768 维。
- 索引配置:为消除规模差异,三者均在相同硬件条件下建立索引:ES mapping 定义 dense_vector 字段(dims=768),索引类型设为 hnsw(M=32, ef_construction=100);Milvus 创建 HNSW 或 IVF_FLAT 索引(如 {“index_type”:“IVF_FLAT”,“params”:{“nlist”:1024}});PostgreSQL 使用 pgvector 插件,创建 HNSW 或 IVFFlat 索引:
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 1024);
其中,HNSW 索引可获得较高召回但构建缓慢、占用内存多,IVFFlat 提升查询速度但略损精度。
- 基准工具:可使用开源工具 VectorDBBench、ANN-Benchmarks或自定义测试脚本。测试指标包括 Top-K 命中率(Recall)、吞吐量(QPS)与延迟等。
Python 查询示例:
# Milvus 查询示例
from pymilvus import Collection, connections
connections.connect(alias="default", host="127.0.0.1", port="19530")
collection = Collection("my_collection")
query_vec = [0.1] * 768
results = collection.search([query_vec], "vector_field", param={"metric_type": "L2", "params": {"nprobe": 10}}, limit=5)
print([hit.id for hit in results[0]])# PostgreSQL (pgvector) 查询示例
import psycopg2
conn = psycopg2.connect("dbname=test")
cursor = conn.cursor()
cursor.execute("SELECT id FROM items ORDER BY embedding <-> %s LIMIT 5;", (query_vec,))
print([row[0] for row in cursor.fetchall()])# ES 查询示例
from elasticsearch import Elasticsearch
es = Elasticsearch()
body = {"size":5, "query": {"knn": {"vector_field": {"vector": query_vec, "k":5, "num_candidates":100}}}}
res = es.search(index="my_index", body=body)
print([hit["_id"] for hit in res["hits"]["hits"]])
向量检索
ES
ES 8.0及以上版本新增向量近邻检索k-nearest neighbor(kNN)search功能,示例:
{"settings": {"number_of_shards": 6,"number_of_replicas": 1},"mappings": {"properties": {"id": {"type": "keyword"},"vector": {"type": "dense_vector","dims": 960, // 最高支持2048维度"index": true,"similarity": "cosine", // 支持 cosine, dot_product, l2_norm"element_type": "float", // 支持 float, byte "index_options": { // hnsw 高级参数配置"type": "hnsw","m": 16,"ef_construction": 100}}}}
}
向量检索支持的索引类型:
- dense_vector:暴力搜索,存储原始向量,查询时计算目标向量与所有向量的距离(如余弦相似度、欧氏距离);无需额外索引结构,数据写入简单。查询性能随数据量线性下降,适合小规模数据(如数万条)
- HNSW:Hierarchical Navigable Small World,基于图的近似最近邻(ANN)算法,通过多层图结构加速搜索;查询速度快(对数时间复杂度),适合大规模数据;需要额外存储索引,写入速度较慢。
- IVF:Inverted File System,通过聚类将向量分到多个桶(Voronoi 单元),搜索时仅计算目标桶内的向量;适合超大规模数据(亿级以上);需要训练聚类中心,写入延迟较高。
参考
- 腾讯云 ES 8 向量化语义混合检索测试指南
- Elasticsearch 8.8 原生向量检索性能测试
- Elasticsearch向量检索的性能测试和比较
- 使用Elasticsearch的向量近邻检索(kNN)功能
- 知识库文档检索,ES精确检索与Faiss向量检索测试
- https://discuss.elastic.co/t/elasticseach-default-similairty-algorithm-and-bm25-giving-same-results/152470
Milvus
Milvus的强项。
索引类型:
- HNSW
- IVF
参考:
- https://milvus.io/docs/v2.0.x/build_index.md
PG
插件:pg_vector和pg_embdding,基于Faiss(向量数据库)的IVF Flat索引。
参考
- https://zhuanlan.zhihu.com/p/4859988545
全文检索
ES
ES的强项,基于倒排索引。
中文全文检索
需要引入中文分词器:
- IK:默认,两种颗粒度的拆分:
ik_smart
:会做最粗粒度的拆分;ik_max_word
:会将文本做最细粒度的拆分;
- smartCN:
- HanLP:
- jieba:
参考
- https://zhuanlan.zhihu.com/p/13723417907
Milvus
检索+排序;使用 BM25 算法进行相关性评分;
适用于全文检索的 Collection,其 Schema 必须包括三个必要字段:
- 唯一标识 Collection 中每个实体的主字段。
- 一个VARCHAR 字段,用于存储原始文本文档,其enable_analyzer 属性设置为True 。这允许 Milvus 将文本标记为特定术语,以便进行函数处理。
- 一个SPARSE_FLOAT_VECTOR 字段,预留用于存储稀疏嵌入,Milvus 将为VARCHAR 字段自动生成稀疏嵌入。
Milvus 2.5 集成高性能搜索引擎库 Tantivy,并内置 Sparse-BM25 算法,首次实现原生全文检索功能:
- 内置基于 tantivy 构建的分词器:无需额外预处理,通过内置分词器(Analyzer)与稀疏向量提取能力,Milvus 可直接接受文本输入,自动完成分词、停用词过滤与稀疏向量提取,无需依赖外部模型(如BGE-M3等)。
- 实时 BM25 统计:数据插入时动态更新词频(TF)与逆文档频率(IDF),确保搜索结果的实时性与准确性。
- 混合搜索性能增强:基于近似最近邻(Approximate Nearest Neighbor,ANN)算法的稀疏向量检索,性能远超传统关键词系统,支持亿级数据毫秒级响应,同时兼容与稠密向量的混合查询。
对比:BM25和Sparse-BM25
BM25采用Sparse Vector,优势,包括但不限于:
- 对长上下文Query可构建图索引来加速搜索;
- 基于量化和WAND的
drop_ratio
等技术手段做近似匹配来提升性能; - 统一语义检索和全文检索的表达方式,使用体验以及技术优化。
rerank使用 RRF(Reciprocal Rank Fusion) 算法:融合向量和文本检索结果,重新优化排序和权重分配,提升数据召回率和精确性。
参考:
- https://milvus.io/docs/zh/full_text_search_with_milvus.md
- https://milvus.io/docs/zh/full-text-search.md
- https://zilliz.com.cn/blog/semantic-search-vs-full-text-search-which-one-should-i-choose-with-milvus-2-5
- https://xie.infoq.cn/article/2d6c98ec75578495365680363
- https://help.aliyun.com/zh/milvus/use-cases/full-text-retrieval-by-milvus-bm25-algorithm-and-application-of-hybrid-retrieval-to-rag-system
中文全文检索
{"type": "english"}
:standard 分词器,
{"type": "chinese"}
:针对中文文本,基于上下文分词并过滤非汉字字符,使用 jieba;Filter采用cnalphanumonly(仅保留汉字和字母数字)。
TODO:
- 读、写性能(向量检索、全文检索)
- 高可用部署的硬件需求
PG
全文检索=匹配+亲和(rank)。
可实现小规模数据量的全文检索功能。
优点:轻量级
索引类型:
- GIN:通用倒排索引,Generalized Inverted Index,官方推荐
- GiST:通用搜索树,Generalized Search Trees
- RUM:https://github.com/postgrespro/rum
基本Query:
- Simple Query:
@@
SELECT * FROM documents WHERE to_tsvector('english', content) @@ to_tsquery('search_term');
- Phrase Search:
& for AND, | for OR, and ! for NOT
SELECT * FROM documents WHERE to_tsvector('english', content) @@ to_tsquery('word1 & word2');
高级Query:
- Ranked Search:
ts_rank
SELECT *, ts_rank(to_tsvector('english', content), to_tsquery('search_term')) AS rank
FROM documents
WHERE to_tsvector('english', content) @@ to_tsquery('search_term')
ORDER BY rank DESC;
- Proximity Search:
<->
SELECT * FROM documents WHERE to_tsvector('english', content) @@ to_tsquery('word1 <-> word2');
- Weighted Search:
setweight
SELECT *, ts_rank_cd(setweight(to_tsvector('a', title), 'A') || setweight(to_tsvector('b', content), 'B'), to_tsquery('search_term')) AS rank
FROM documents
WHERE to_tsvector('english', content) @@ to_tsquery('search_term')
ORDER BY rank DESC;
中文全文检索
安装插件:
- zhparser:https://github.com/amutu/zhparser,推荐,阿里云的RDS默认包含。
- jieba:https://github.com/jaiminpan/pg_jieba、
- PGroonga:https://github.com/pgroonga/pgroonga,star, https://blog.csdn.net/weixin_44957042/article/details/138917123
参考
- 全文检索:http://www.postgres.cn/docs/9.3/textsearch.html
- 用PostgreSQL 做实时高效 搜索引擎 - 全文检索、模糊查询、正则查询、相似查询、ADHOC查询
- https://help.aliyun.com/zh/analyticdb/analyticdb-for-postgresql/user-guide/
- https://www.cnblogs.com/zhenbianshu/p/7795247.html
- https://cloud.tencent.com/developer/article/1430039
对比
主要差异:
特性 | ES | Milvus | PostgreSQL+pgvector |
---|---|---|---|
向量检索 | 支持dense_vector,但性能有限,适合小规模或简单场景 | 专为高维向量优化,支持GPU加速、多种索引算法,性能更强 | |
向量索引类型 | 默认使用HNSW图算法(可量化为int8_hnsw或int4_hnsw)。支持精确搜索(脚本评分)。 | 支持多种ANNS索引:FLAT、IVF_FLAT、IVF_SQ8、IVF_PQ、HNSW、RHNSW_FLAT/SQ/PQ、ANNOY。FLAT保证100%准确率但查询缓慢。 | 支持HNSW和IVFFlat;默认无索引时为精确扫描。HNSW索引构建缓慢但查询精度高,IVFFlat平衡速度和内存 |
距离度量 | 支持L2、IP(内积)、余弦等(可通过脚本自定义)。 | 支持L2、IP等常用度量,二进制向量还支持Jaccard、Hamming等。 | 支持L2、IP、余弦(Cosine)等距离 |
向量检索精度 | 近似搜索,召回率依赖HNSW参数(ef、M)。一般可达到~90%以上(需要调整参数)。可使用精确脚本评分保证准确性。 | FLAT索引可达100%召回;ANN索引可调nlist/nprobe以平衡速度和召回率,一般可>90%。 | 无索引时为精确搜索(100%召回);HNSW索引召回高但构建慢;IVF-Flat部分匹配,召回略低 |
检索速度(QPS/延迟) | 集群优化良好。在高召回场景下吞吐量中等,延迟取决于硬件和参数。 | 专为大规模向量检索设计,支持GPU加速。Milvus在千维向量和大数据量场景下查询速度很高(可达数千QPS),吞吐量通常优于通用数据库。 | 作为通用DB,向量检索相对较慢。在类似参数下,pgvector的QPS远低于专用向量库 |
内存/存储占用 | 向量数据存储在pagecache中。支持量化(int8)来减小索引大小。HNSW索引在Lucene节点中占用额外内存。 | HNSW/FLAT索引需要大量内存存储图或向量本身;IVF+PQ/SQ8索引压缩程度高,减小内存占用。总体而言,专用向量DB在索引存储上更灵活。 | HNSW索引构建缓慢且占内存;IVFFlat需要存储聚类中心(lists)数据。所有向量数据以列方式存储在表中,数据量大时占用存储也较高 |
集群扩展性 | 内置分片和副本机制elastic.co。每个索引可划分多个主分片(shard),每个分片可有副本,以分布式方式扩展。成熟的集群管理和自动重平衡机制。 | 天生分布式架构:分离计算层与存储层,多节点协同。Milvus可自动将数据分片(Shard)分布到不同节点并在节点扩缩容时自动重平衡milvus.io。支持多数据节点和查询节点水平扩展。 | PostgreSQL本身不支持自动水平分片;通常通过分区表和扩展(如Citus)实现横向扩展milvus.io。原生只有主从复制,用于高可用,但不自动负载均衡。部署运维相对简单,但大规模数据面临扩展挑战 |
全文检索支持 | 强大的倒排索引和分析器支持全文检索。默认使用BM25相关性算法,分析器丰富,适合复杂查询和高效排名。 | 2.5版本起,Milvus引入BM25全文索引,支持关键词和短语检索。可与向量检索结合,实现hybrid搜索。 | PostgreSQL提供tsvector/tsquery全文搜索,基于倒排索引(GIN)执行关键词检索。默认相关性计算为TF-IDF风格(ts_rank),可通过扩展(如VectorChord-BM25)引入BM25排序 |
场景定位 | 全文搜索+结构化数据分析+基础向量检索 | 大规模向量相似性搜索+AI/ML场景 |
对比项解读:
- 向量检索精度:在召回率(Recall)方面,所有系统的精确搜索(如Milvus的FLAT、PostgreSQL无索引扫描)均可达到 100%。使用近似索引时,精度取决于参数:Milvus的HNSW/IVF可通过增大
nprobe
或ef
值获得高召回;ES的HNSW需要设置较高ef
才能接近真实最近邻。实践中,如果要求召回≥98%,Milvus和ES都能达到,而pgvector的近似索引在高维场景中通常需要较多参数调优。 - 检索速度(QPS/延迟):通用数据库(PostgreSQL、MongoDB、OpenSearch)在高召回向量搜索场景下吞吐量和延迟都明显落后于专用向量库。在相同召回条件下,其查询吞吐量比pgvector提供的PostgreSQL快近10倍。Milvus和其他专业库通常在大规模数据上能提供更高QPS。例如,Milvus官方示例在百万级数据上进行HNSW比较,展示出较高吞吐(云端部署时需注意资源配置)。ES查询速度介于两者之间:其优化良好的Lucene索引在中等规模下表现良好,但向量检索耗费内存和CPU,相比纯向量库略显逊色。综合而言,在大数据量和高吞吐场景下,Milvus通常表现最好,其次是ES,pgvector适合数据量中等、延迟要求不极端的场景。
- 全文检索:
- 内存与存储占用:向量检索一般需要大量内存。ES要求所有向量索引数据在节点的页缓存中才能高效查询,量化(Int8)可降低索引大小。Milvus的HNSW/FLAT索引需要在RAM中存储图结构或完整向量;使用IVF+PQ/SQ8等压缩索引可显著减少内存使用。PostgreSQL将向量直接存储在表中,HNSW索引占用额外内存较大;IVF索引还需要保存聚类单元的中心点数据。一般来说,专业向量库在内存管理上更灵活,但部署时需注意节点规格。
- 系统扩展与运维:ES原生支持集群分片和副本,运维工具成熟(如ES Operator、Elastic Cloud)。Milvus也提供完整的分布式架构,可水平扩展;其自动重平衡功能在节点增减时保证负载均匀。PostgreSQL本身单节点性能优秀,但需额外方案(读写分离、Citus等)才能实现横向扩展。综合运维复杂度:Elastic、Milvus都需要管理多服务节点,Milvus配置稍复杂;PG相对简单但可扩展性较差。
结论: 综合来看,Milvus 在大规模向量检索场景中性能最佳,支持丰富索引类型和自动扩展,适合对吞吐和低延迟要求高的应用;ES 拥有成熟的全文搜索能力,适合混合结构化、文本和向量的检索(内置 BM25、倒排索引);PostgreSQL + pgvector 则为传统关系库用户提供便利,适合数据量适中、方便集成的场景,但其向量查询性能明显弱于专用向量库(多项基准显示 QPS 低于 Milvus)。选择哪种方案取决于具体需求:如果需要同时做关键词和语义搜索,ES 可快速构建混合应用;如果追求最大化向量检索性能与扩展性,Milvus 是更优选;如果已有 PostgreSQL 生态且对吞吐要求不极端,则 pgvector 提供足够的功能。
附录
Tantivy
Rust语言编写,Lucene平替,开源高性能搜索引擎库,可被集成到各种数据库中,包括:
- Milvus
- PG
- MyScaleDB:针对向量搜索进行优化的ClickHouse开源分支
https://docs.rs/tantivy/latest/tantivy/
https://tantivy-search.github.io/bench/
https://github.com/dromara/MilvusPlus/blob/main/Tantivy文本匹配.md
https://www.yicaiai.com/news/article/670738554ddd79f11a6e2770
https://www.53ai.com/news/hangyeyingyong/2024053165894.html
关键功能
- BM25相关性评分:Elasticsearch、Lucene和Solr都将BM25用作默认相关性排名算法。BM25分数评估文本搜索的准确性和相关性,增强用户搜索体验。
- 可配置标记器:此功能支持各种语言标记器,满足用户多样化的标记化需求。
- 自然语言查询:用户可以使用AND、OR和IN等关键字灵活地组合文本查询,降低SQL语句编写的复杂性。
ParadeDB
GitHub。
ParadeDB is a full text search engine built for Postgres. Powered by an extension called pg_search, ParadeDB embeds Tantivy, a Rust-based Lucene alternative, inside Postgres.
基于pg_search+ Tantivy。
参考
- https://iniakunhuda.medium.com/postgresql-full-text-search-a-powerful-alternative-to-elasticsearch-for-small-to-medium-d9524e001fe0
- https://risingwave.com/blog/implementing-high-performance-full-text-search-in-postgres/
检索
包括:
- Semantic Search:语义搜索
- Keyword Search:关键词搜索
- Full Text Search:FTS,全文搜索
- Vector Search:向量搜索
- Exact Match Search:精确搜索
- Fuzzy Search:模糊搜索
检索类型 | 语义搜索 | 关键词搜索 | 全文搜索 | 向量搜索 | 精确搜索 | 模糊搜索 |
---|---|---|---|---|---|---|
核心 | 理解查询的语义意图,而非字面匹配 | 基于精确关键词匹配(词袋模型) | 对文本内容进行全面扫描和索引,支持复杂查询 | 将数据转换为向量,计算向量距离(如余弦相似度) | 完全匹配字段值(区分大小写和格式) | 容忍拼写错误或近似匹配 |
技术 | 使用NLP模型(如BERT、GPT)生成dense向量,计算语义相似度 | 倒排索引、TF-IDF、BM25等稀疏向量方法 | 分词(Tokenization)、倒排索引、支持布尔逻辑(AND/OR/NOT) | DenseVector(语义搜索常用,如BERT)SparseVector(全文搜索常用,如TF-IDF) | 哈希索引、B树索引 | 编辑距离(LevenshteinDistance)N-gram分词(如“apple”和“appel”可能匹配) |
特点 | 能处理同义词、近义词(如“苹果”和“iPhone”)自然语言查询友好(如“如何做番茄炒蛋”) | 严格匹配关键词(如搜索“Java”不会返回“Coffee”)无法处理语义扩展 | 支持模糊匹配、短语匹配、通配符等关键词搜索的增强版 | 适合非结构化数据计算开销较大 | 结果100%精确不支持任何模糊性 | 容错性强(如搜索“Misissippi”仍能匹配“Mississippi”) |
应用 | 智能客服、知识库问答、推荐系统 | 传统搜索引擎、数据库查询(如SQL的LIKE ) | 文档检索、日志分析 | 相似图片搜索、语义检索 | 数据库主键查询、验证码校验 | 用户输入纠错、搜索引擎的“你是不是想找” |
工具 | ES向量检索、FAISS、Milvus(结合语义模型) | ES的全文检索、MySQL的全文索引 | Elasticsearch、Solr、PostgreSQL的tsvector | Milvus、FAISS、Weaviate | 所有关系型数据库 | ES的fuzzy 查询、Redis的模糊键匹配 |
其他:
- Hybrid Search:混合搜索,结合关键词搜索和向量搜索,增强搜索结果的相关性;
- Geospatial Search:地理位置搜索,基于经纬度或地理范围,如:ES 的geo_distance、PostGIS;
- Temporal Search:时间范围搜索,按时间戳过滤;
- Multimodal Search:多模态搜索,跨模态检索(如用文本搜索图片,或用图片搜索文本),如CLIP等跨模态模型生成的向量。
Dense Vector v.s Sparse Vector
稠密向量和稀疏向量,向量表示的两种主要形式。
特征 | Dense Vector | Sparse Vector |
---|---|---|
生成 | 由神经网络模型生成 | 基于词袋模型或n-gram |
维度 | 固定维度(通常50-1000维),每个维度都有含义但不直接可解释 | 极高维度(可能数万到数百万维),维度对应特定词或术语 |
非零值 | 几乎全部维度都有非零值 | 绝大多数维度为零值 |
存储 | 存储所有维度的值,需要较大存储空间 | 只存储非零值及其位置,存储空间需求小 |
计算 | 适合计算余弦相似度等度量 | 计算效率高(稀疏性) |
语义 | 捕获深层次语义关系 | 基于词频或出现统计 |
典型应用 | ES向量检索、语义相似度、语义搜索 | Milvus全文检索、传统文本检索、关键词搜索 |
其他
https://db-engines.com/en/ranking/vector+dbms