当前位置: 首页 > news >正文

如何使用 Elasticsearch 进行全文检索和向量检索

如何使用 Elasticsearch 进行全文检索和向量检索

Posted on 2026-06-20 15:08  work hard work smart  阅读(0)  评论(0)    收藏  举报

Elasticsearch 具有全文检索能力和向量检索能力。全文检索适合解决“关键词匹配、分词、相关性排序”的问题,向量检索适合解决“语义相似、意思接近但表达不同”的问题。

在实际的 AI 应用,尤其是 RAG 知识库场景中,这两种检索方式通常不会孤立使用,而是会组合起来使用:

  • 全文检索:找到和用户问题中关键词高度相关的内容
  • 向量检索:找到语义上相似的内容
  • 混合检索:同时利用关键词匹配和语义匹配,提高召回质量

本文单独介绍如何使用 Elasticsearch 实现全文检索和向量检索。


一、为什么 Elasticsearch 既能做全文检索,也能做向量检索?

Elasticsearch 最早是典型的全文搜索引擎,底层基于 Lucene,擅长处理倒排索引、分词、相关性评分等搜索场景。

随着 AI 和大模型应用的发展,Elasticsearch 也支持了向量字段和向量相似度搜索,可以将文本 embedding 之后的向量存储在 ES 中,并通过相似度算法进行检索。

所以现在的 Elasticsearch 可以同时支持两类数据:

{"content": "Elasticsearch 是一个分布式搜索和分析引擎","content_vector": [0.12, 0.31, -0.22]
}

其中:

  • content 用于全文检索
  • content_vector 用于向量检索

二、准备索引结构

假设我们要构建一个知识库,每条文档切片包含以下字段:

  • doc_id:文档 ID
  • chunk_id:切片 ID
  • title:标题
  • content:文本内容
  • content_vector:文本向量
  • metadata:额外元数据

可以创建如下索引:

PUT knowledge_chunks
{"mappings": {"properties": {"doc_id": {"type": "keyword"},"chunk_id": {"type": "keyword"},"title": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"},"content": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"},"content_vector": {"type": "dense_vector","dims": 1024,"index": true,"similarity": "cosine"},"metadata": {"type": "object","enabled": true},"created_at": {"type": "date"}}}
}

这里有几个关键点。

1. text 字段用于全文检索

"content": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"
}

如果是中文场景,通常会配合 IK 分词器:

  • ik_max_word:索引阶段尽可能细粒度分词,提高召回
  • ik_smart:搜索阶段更智能地分词,减少噪音

2. dense_vector 字段用于向量检索

"content_vector": {"type": "dense_vector","dims": 1024,"index": true,"similarity": "cosine"
}

其中:

  • dims 要和 embedding 模型输出维度一致
  • index: true 表示支持近似最近邻检索
  • similarity: cosine 表示使用余弦相似度

不同 embedding 模型的维度不同,比如 384、768、1024、1536 等,建索引时一定要保持一致。


三、写入文档和向量

在写入 ES 之前,需要先对文档进行切片,然后对每个切片生成 embedding。

例如原始文档是:

Elasticsearch 是一个分布式搜索和分析引擎,支持全文检索、结构化查询、聚合分析和向量检索。

经过 embedding 模型处理后,得到一个向量:

[0.12, -0.04, 0.33]

然后写入 ES:

POST knowledge_chunks/_doc/1
{"doc_id": "doc_001","chunk_id": "chunk_001","title": "Elasticsearch 简介","content": "Elasticsearch 是一个分布式搜索和分析引擎,支持全文检索、结构化查询、聚合分析和向量检索。","content_vector": [0.12, -0.04, 0.33],"metadata": {"source": "es-guide.md","page": 1},"created_at": "2026-06-20T10:00:00"
}

实际使用时,content_vector 会是完整维度的向量,这里只是简化示例。


四、使用 ES 进行全文检索

全文检索主要依赖 matchmulti_matchbool 等查询。

1. 单字段全文检索

如果只搜索正文内容,可以这样写:

POST knowledge_chunks/_search
{"query": {"match": {"content": "Elasticsearch 如何进行全文检索"}}
}

ES 会对用户输入进行分词,然后到倒排索引中查找相关文档,并根据 BM25 算法计算相关性得分。

2. 多字段全文检索

在知识库场景中,标题和正文都可能命中,所以更常见的是 multi_match

POST knowledge_chunks/_search
{"query": {"multi_match": {"query": "Elasticsearch 向量检索怎么做","fields": ["title^2","content"]}}
}

这里的:

"title^2"

表示标题字段权重更高。如果标题命中,得分会比正文命中更高。

3. 带过滤条件的全文检索

如果只想搜索某个文档、某个知识库、某个用户的数据,可以加 filter

POST knowledge_chunks/_search
{"query": {"bool": {"must": [{"multi_match": {"query": "全文检索和向量检索的区别","fields": ["title^2","content"]}}],"filter": [{"term": {"doc_id": "doc_001"}}]}}
}

must 会影响相关性评分,filter 不参与评分,适合放权限、租户、文档 ID、知识库 ID 这类精确条件。


五、使用 ES 进行向量检索

向量检索的核心思路是:

  1. 用户输入一个问题
  2. 使用 embedding 模型将问题转换成向量
  3. 用问题向量到 ES 中查找最相似的文档向量

例如用户问题是:

ES 能不能做语义搜索?

经过 embedding 模型后得到:

[0.21, -0.13, 0.08]

然后使用 knn 查询:

POST knowledge_chunks/_search
{"knn": {"field": "content_vector","query_vector": [0.21, -0.13, 0.08],"k": 5,"num_candidates": 100},"_source": ["doc_id","chunk_id","title","content","metadata"]
}

参数说明:

  • field:向量字段名
  • query_vector:用户问题的向量
  • k:最终返回最相似的前 N 条
  • num_candidates:候选数量,越大召回越充分,但查询成本也越高

一般来说:

num_candidates >= k

例如:

k = 5
num_candidates = 100

表示先从近似向量索引中召回 100 个候选,再返回最相似的 5 个。


六、带过滤条件的向量检索

实际业务中,向量检索通常也需要过滤。例如只检索某个知识库、某个用户、某个文件下的内容。

可以这样写:

POST knowledge_chunks/_search
{"knn": {"field": "content_vector","query_vector": [0.21, -0.13, 0.08],"k": 5,"num_candidates": 100,"filter": {"term": {"doc_id": "doc_001"}}},"_source": ["doc_id","chunk_id","title","content","metadata"]
}

这样 ES 只会在符合过滤条件的文档中进行向量相似度检索。


七、全文检索和向量检索的区别

全文检索和向量检索解决的是两类不同问题。

对比项 全文检索 向量检索
核心能力 关键词匹配 语义相似
底层方式 倒排索引 向量相似度
典型算法 BM25 cosine、dot_product、l2_norm
优点 精确、可解释、适合关键词 能理解语义,适合同义表达
缺点 对同义词、改写表达不敏感 结果可解释性较弱,依赖 embedding 质量
适合场景 标题、术语、错误码、编号、关键词 问答、知识库、语义搜索、RAG

举个例子。

用户搜索:

ES 怎么做语义搜索?

如果文档里写的是:

Elasticsearch 支持基于 dense_vector 的相似度召回。

全文检索可能因为关键词不完全匹配而得分不高。

但向量检索可以理解“语义搜索”和“相似度召回”之间的语义关系,从而更容易召回这条内容。

反过来,如果用户搜索:

ERROR_CODE_10086

这种精确错误码,全文检索通常会比向量检索更可靠。


八、混合检索:同时使用全文检索和向量检索

在 RAG 场景中,单独使用全文检索或者单独使用向量检索都可能有问题。

只用全文检索:

  • 关键词不匹配时召回不到
  • 同义表达、改写表达效果不好

只用向量检索:

  • 对专有名词、编号、代码、错误码不一定稳定
  • 结果可解释性弱
  • embedding 模型质量会直接影响召回效果

所以更推荐使用混合检索。

常见做法有两种。

方案一:分别检索,再合并排序

先执行全文检索:

POST knowledge_chunks/_search
{"size": 10,"query": {"multi_match": {"query": "Elasticsearch 如何实现向量检索","fields": ["title^2","content"]}}
}

再执行向量检索:

POST knowledge_chunks/_search
{"knn": {"field": "content_vector","query_vector": [0.21, -0.13, 0.08],"k": 10,"num_candidates": 100}
}

然后在应用层合并结果:

  1. 根据 chunk_id 去重
  2. 对全文检索分数和向量检索分数做归一化
  3. 按加权分数重新排序
  4. 取 Top N 结果交给大模型

伪代码如下:

List<SearchResult> textResults = elasticsearchFullTextSearch(query);
List<SearchResult> vectorResults = elasticsearchVectorSearch(queryVector);Map<String, SearchResult> merged = new HashMap<>();for (SearchResult result : textResults) {result.setTextScore(normalize(result.getScore()));merged.put(result.getChunkId(), result);
}for (SearchResult result : vectorResults) {SearchResult existing = merged.get(result.getChunkId());if (existing == null) {result.setVectorScore(normalize(result.getScore()));merged.put(result.getChunkId(), result);} else {existing.setVectorScore(normalize(result.getScore()));}
}List<SearchResult> finalResults = merged.values().stream().peek(result -> result.setFinalScore(result.getTextScore() * 0.4 + result.getVectorScore() * 0.6)).sorted(Comparator.comparing(SearchResult::getFinalScore).reversed()).limit(5).toList();

这种方式最灵活,也最容易控制业务逻辑。

方案二:使用 ES 的混合查询

部分 Elasticsearch 版本支持在一次查询中同时使用 queryknn

POST knowledge_chunks/_search
{"size": 5,"query": {"multi_match": {"query": "Elasticsearch 如何实现向量检索","fields": ["title^2","content"]}},"knn": {"field": "content_vector","query_vector": [0.21, -0.13, 0.08],"k": 10,"num_candidates": 100}
}

这种方式写起来更简单,但是不同 ES 版本对混合查询的支持方式可能不同,实际使用时需要结合具体版本确认。

如果业务需要更精细的去重、归一化、重排序、权限过滤,通常还是建议在应用层分别检索后合并。


九、RAG 场景中的推荐流程

在知识库问答系统中,可以采用如下流程:

用户问题|v
问题改写 / 查询增强|v
生成 query embedding|v
全文检索 + 向量检索|v
结果合并去重|v
重排序 rerank|v
拼接上下文|v
调用大模型生成答案

其中 ES 主要负责:

  • 存储文档切片
  • 存储切片向量
  • 执行全文检索
  • 执行向量检索
  • 支持过滤条件,比如知识库 ID、文件 ID、用户 ID

大模型主要负责:

  • 理解用户问题
  • 生成 query embedding
  • 根据召回内容生成自然语言答案

十、在 Java 中如何调用

如果项目是 Java 或 Spring Boot,可以通过 Elasticsearch Java Client 调用。

全文检索示例:

SearchResponse<KnowledgeChunk> response = client.search(s -> s.index("knowledge_chunks").query(q -> q.multiMatch(m -> m.query("Elasticsearch 如何实现全文检索").fields("title^2", "content"))).size(5),KnowledgeChunk.class
);

向量检索示例:

SearchResponse<KnowledgeChunk> response = client.search(s -> s.index("knowledge_chunks").knn(knn -> knn.field("content_vector").queryVector(queryVector).k(5).numCandidates(100)).source(src -> src.filter(f -> f.includes("doc_id", "chunk_id", "title", "content", "metadata"))),KnowledgeChunk.class
);

如果使用 Spring AI,也可以把 Elasticsearch 作为 VectorStore 的实现,让框架帮我们封装一部分向量写入和相似度搜索逻辑。


十一、实践建议

1. 文档切片不要太大

如果切片太大,召回结果会包含很多无关内容;如果切片太小,又可能缺少上下文。

常见切片大小可以从下面范围开始调试:

chunk size: 500 ~ 1000 tokens
overlap: 50 ~ 150 tokens

具体大小要结合业务文档类型调整。

2. 向量维度必须和索引 mapping 一致

如果 mapping 中定义:

"dims": 1024

那么写入的每个向量都必须是 1024 维,否则会写入失败。

3. 不要只依赖向量检索

向量检索擅长语义召回,但对于以下内容,全文检索通常更可靠:

  • 订单号
  • 错误码
  • 类名
  • 方法名
  • API 名称
  • 专有名词
  • 精确短语

所以生产环境更推荐混合检索。

4. 需要做权限过滤

如果是多用户、多租户知识库,检索时必须增加过滤条件,例如:

"filter": {"term": {"user_id": "user_001"}
}

避免用户检索到不属于自己的文档内容。

5. 检索后最好增加 rerank

全文检索和向量检索负责召回,召回结果不一定是最终最适合给大模型的内容。

可以在召回 Top 20 或 Top 50 后,再通过 rerank 模型重新排序,最后取 Top 5 或 Top 10 作为上下文。


十二、总结

Elasticsearch 现在不仅可以做传统的全文检索,也可以做向量检索,非常适合作为 RAG 知识库的检索底座。

全文检索适合解决关键词匹配问题,向量检索适合解决语义相似问题。两者各有优势,也各有短板。

在真实业务中,更推荐使用混合检索:

全文检索负责精确匹配
向量检索负责语义召回
应用层负责合并、去重、重排序
大模型负责基于上下文生成答案

这样既能保证关键词、术语、错误码等精确内容不丢失,也能提升用户自然语言提问时的语义召回效果。

对于 AI 知识库、智能问答、企业文档搜索等场景,Elasticsearch 的全文检索 + 向量检索组合,是一个非常实用且容易落地的方案。