检索引擎深度对比:Elasticsearch vs Milvus vs Redis 在 RAG 中的定位
检索引擎深度对比:Elasticsearch vs Milvus vs Redis 在 RAG 中的定位
RAG 选检索引擎是第一个也是最重要的架构决策。选错了,回头改的成本远超重新做。但很多团队做这个决策时,靠的是"听过这个名字"或者"之前用过",而不是基于场景分析的技术选型。
我把 Elasticsearch、Milvus 和 Redis(RediSearch)放在 RAG 的上下文中做了对比。结论不是哪个更好,而是哪种场景该用哪个。
一、深度引言与场景痛点
Elasticsearch 是为全文搜索设计的全文搜索引擎,向量搜索是后来加的。Milvus 是从头为向量搜索设计的专用向量数据库。Redis 是内存数据结构存储,向量搜索是它的一个模块。
设计哲学的差异导致了它们在不同场景下的表现天差地别。一个团队之前用 ES 做日志搜索,顺手拿它做 RAG 检索,半年后发现延迟降不下来、索引膨胀到内存放不下——这就是没理解引擎定位。
二、底层机制与原理深度剖析
| 维度 | Elasticsearch | Milvus | Redis |
|---|---|---|---|
| 向量搜索速度 (百万级) | 中 | 极快 | 快 |
| 关键词搜索 | 极强 | 弱 | 中 |
| 混合检索 | 强 (内置) | 需自行实现 | 中 (FILTER) |
| 内存效率 | 中 | 高 | 低 (全内存) |
| 运维复杂度 | 高 (JVM调优) | 中 | 低 |
| 扩展性 | 强 (分片) | 极强 (分布式) | 中 (集群) |
| 学习曲线 | 陡 | 中 | 平缓 |
| 最佳向量规模 | 百万级 | 亿级 | 十万-百万级 |
三、生产级代码实现
ES 的强项是 Lucene 的倒排索引——BM25 算法经过 20 年打磨,在关键词匹配上没有对手。如果你的 RAG 场景有大量专有名词、错误码、API 名,ES 的关键词通道可以让召回率提升 20% 以上。
但 ES 的向量搜索是"附加功能"。HNSW 实现在 8.x 才稳定,kNN 搜索在大数据量下性能一般。JVM 的内存管理让 ES 的内存占用偏高——2GB 堆是起步价。
ES 适合的场景:技术文档搜索(错误码、API)、电商搜索(品牌名、型号)、需要复杂过滤(价格区间、分类标签)的混合查询。不适合的场景:纯向量语义搜索、亿级以上向量规模、极致低延迟(<10ms)。
四、边界分析与架构权衡
Milvus 是从向量搜索起家的。它的索引类型(IVF_FLAT、IVF_SQ8、HNSW、DISKANN)和查询优化是为向量搜索深度定制的。在百万级以上向量规模,Milvus 的搜索速度是 ES 的 5-10 倍。
Milvus 的分布式架构也很成熟:Proxy、QueryNode、DataNode、IndexNode 分层设计,可以独立扩缩。QueryNode 不够加 QueryNode,IndexNode 慢了加 IndexNode。
但 Milvus 的关键词搜索很弱。它没有倒排索引,靠标量过滤做关键词匹配效率低。如果你需要"向量语义 + 精确关键词"的混合检索,需要在 Milvus 外再搭一个关键词通道。
Milvus 适合的场景:语义问答(不需要精确关键词)、大规模知识库(百万+)、需要高召回率的推荐系统。不适合的场景:小规模数据(<10万)、需要复杂关键词过滤、团队没有 K8s 运维能力。
结论
Redis 做向量检索最大的优势是低延迟——纯内存操作,单次搜索通常 <5ms。如果 RAG 的延迟预算只有 1 秒,Redis 的检索部分几乎可以忽略不计。
Redis 的另一个隐藏优势是"一物多用"。你本来就需要 Redis 做缓存、Session 存储、限流计数器,加上 RediSearch 模块后,向量搜索和 KV 缓存在同一个进程里。减少了一个服务,运维复杂度直接降一档。
但 Redis 的纯内存架构是把双刃剑。百万级向量 + HNSW 索引,内存占用可能到 10GB+。成本高于磁盘方案。如果你的向量数据增长很快,Redis 可能不是长期方案。
Redis 适合的场景:中规模向量(<100万)、使用 Redis 做缓存的团队、延迟严苛(<50ms 全链路)、PoC 阶段快速验证。不适合的场景:十亿级向量、已有专用缓存层、预算有限的数据规模不限增长。
六、场景选型决策树
from enum import Enum from dataclasses import dataclass class EngineType(Enum): ELASTICSEARCH = "elasticsearch" MILVUS = "milvus" REDIS = "redis" @dataclass class RetrievalRequirements: expected_doc_count: int vector_dim: int need_keyword_search: bool need_complex_filtering: bool max_latency_ms: int use_existing_redis: bool budget_sensitive: bool team_has_k8s_experience: bool def recommend_engine(req: RetrievalRequirements) -> dict: scores = {e: 0 for e in EngineType} # 关键词需求 if req.need_keyword_search: scores[EngineType.ELASTICSEARCH] += 30 scores[EngineType.REDIS] += 15 scores[EngineType.MILVUS] += 0 # 复杂过滤 if req.need_complex_filtering: scores[EngineType.ELASTICSEARCH] += 20 scores[EngineType.MILVUS] += 10 scores[EngineType.REDIS] += 5 # 延迟要求 if req.max_latency_ms < 50: scores[EngineType.REDIS] += 25 scores[EngineType.MILVUS] += 15 scores[EngineType.ELASTICSEARCH] += 5 elif req.max_latency_ms < 200: scores[EngineType.MILVUS] += 20 scores[EngineType.REDIS] += 20 scores[EngineType.ELASTICSEARCH] += 15 # 规模 if req.expected_doc_count > 10_000_000: scores[EngineType.MILVUS] += 30 scores[EngineType.ELASTICSEARCH] += 20 scores[EngineType.REDIS] += 0 elif req.expected_doc_count > 1_000_000: scores[EngineType.MILVUS] += 20 scores[EngineType.ELASTICSEARCH] += 20 scores[EngineType.REDIS] += 5 else: scores[EngineType.REDIS] += 25 scores[EngineType.ELASTICSEARCH] += 20 scores[EngineType.MILVUS] += 15 # 已有 Redis if req.use_existing_redis: scores[EngineType.REDIS] += 20 # 预算 if req.budget_sensitive: scores[EngineType.ELASTICSEARCH] += 15 scores[EngineType.REDIS] += 15 scores[EngineType.MILVUS] -= 5 # K8s 运维能力 if not req.team_has_k8s_experience: scores[EngineType.MILVUS] -= 15 ranked = sorted( [(k, v) for k, v in scores.items()], key=lambda x: x[1], reverse=True ) return { "recommendation": ranked[0][0].value, "scores": {k.value: v for k, v in ranked}, "reason": ( f"推荐 {ranked[0][0].value}。" f"备选 {ranked[1][0].value}。" ), }这个决策引擎把选型从"拍脑袋"变成了"算分数"。虽然分数是主观权重,但至少让决策过程透明了。
七、总结
RAG 的检索引擎选型,核心是认识三个要素:
- 你的数据特征:有没有大量精确词?向量规模多大?增长率如何?
- 你的延迟预算:全链路 1 秒还是 3 秒?检索环节的延迟占比多少?
- 你的运维能力:团队有没有精力再维护一个专用数据库?
ES 适合关键词密集、需要复杂过滤的场景。Milvus 适合大规模纯向量搜索。Redis 适合中小规模、延迟敏感、团队运维能力有限的场景。
我的建议:先用 Redis 做 PoC(部署快、延迟低、和缓存一体化),当向量规模到百万级时评估是否需要迁移 Milvus。ES 只在"非用不可"的场景上——它的运维成本比另外两个都高。
