两种或更多检索方法。一个排序列表。
混合搜索是一种信息检索技术,它将两种或更多搜索方法(例如词汇搜索/lexical 和语义搜索)结合到一个统一的排序列表中,以提升相关性和召回率。最常见的组合是将全文词法搜索与语义向量搜索结合起来。全文词法搜索非常擅长匹配精确的词语和短语,而语义向量搜索则能够理解查询背后的含义。词法搜索提供精准性,语义搜索则能够深入理解用户的潜在意图。
这些方法会在一个查询中同时运行,然后使用专门的融合策略将它们的结果合并成一个统一的排序结果。虽然词法搜索 + 语义搜索是最常见的组合,但混合搜索也可以结合其他方法,例如地理空间搜索 + 语义搜索,甚至文本搜索 + 图像搜索,以满足不同的需求。
为什么混合搜索很重要
混合搜索可以在单一流程中利用不同检索方法的优势,同时弥补各自的不足。现代 AI 必须处理多种模态,包括文本、图像、音频、日志等,并将用户意图与数据连接起来。相关性比以往任何时候都更加重要。例如,在电子商务中,如果搜索体验能够帮助用户快速筛选和细化结果,就可以取得成功;但 AI agent 通常需要一个高度相关的答案来回答问题或执行操作。这就是为什么能够组合和优化检索技术在今天如此重要,它不仅为传统搜索结果提供支持,也为能够提供精准、以数据为依据的响应的对话式 agent 提供支持。
在进一步深入了解混合搜索之前,我们先快速了解一下词汇搜索和语义搜索有何不同,以及为什么它们能够互补。
词汇搜索解析
当你拥有结构良好的数据,并且用户知道自己要找什么时,词汇搜索非常理想。它能够匹配精确的词语,因此具有很高的精准性和可解释性,并依赖相关性评分算法(例如 BM25F)根据查询词的频率和稀有程度对文档进行排序。这种方法能够提供透明的评分,并通过字段 boost、同义词和分析器实现精细的相关性调优。由于没有模型开销,词汇搜索快速且高效,并且通过过滤器和分面,即使在大规模场景下也能稳定执行,不会出现性能下降或完整索引扫描。它尤其适用于结构化查询、稀有词和领域特定语言。

下面是一个简单的词法搜索查询示例:
bash
`
1. GET example-index/_search
2. {
3. "query": {
4. "term": {
5. "text": "blue shoes"
6. }
7. }
8. }
`AI写代码
让我们再来看一个类似的词法搜索示例,这次使用 Elasticsearch Query Language(ES|QL)查询一个烹饪博客。该博客包含各种食谱,并具有包括文本内容、分类数据和数值评分在内的各种属性。
markdown
`
1. FROM cooking_blog METADATA _score
2. | WHERE description:"fluffy pancakes"
3. | KEEP title, description, _score
4. | SORT _score DESC
5. | LIMIT 1000
`AI写代码
这个查询会在 description 字段中搜索包含"fluffy"或"pancakes"(或两者)的文档。默认情况下,ES|QL会在搜索词之间使用 OR 逻辑,因此会匹配包含任意指定词语的文档。你可以使用 KEEP 命令准确指定要在结果中包含哪些字段,并请求 _score 元数据,根据文档与查询的匹配程度对搜索结果进行排序。
通过这个实践教程进一步了解词法搜索。
语义搜索解析
语义搜索根据查询与文档之间的语义相似度来检索结果,而不仅仅像词法搜索那样匹配精确的词语。
Embedding 模型会将文本或其他媒体的含义转换成一种称为向量的数值表示。这些向量 ------ 一组数字 ------ 能够捕捉文本背后的上下文和主题,并存储在类似 Elasticsearch 的向量数据库中。
这样,即使结果与查询之间没有任何完全相同的词语,搜索引擎也能够找到概念上相似的结果。

这种方法特别适用于非结构化数据、探索性查询,以及用户可能不知道应该使用哪些确切词语的场景。开发人员可以利用语义搜索提供更相关的结果,并处理模糊、冗长或含义不明确的表达,同时仍然找到正确的答案。
下面是一个语义搜索查询示例:
bash
`
1. GET example-index/_search
2. {
3. "query": {
4. "semantic": {
5. "field": "inference_field",
6. "query": "blue waterproof trail runners with great grip and a wide toe box"
7. }
8. }
9. }
`AI写代码
当你的映射中包含 semantic_text 类型的字段时,ES|QL 支持语义搜索。文档经过运行在 inference endpoint 上的底层模型处理后,你就可以执行语义搜索。下面是一个针对 semantic_description 字段的自然语言查询示例:
sql
`
1. FROM cooking_blog METADATA _score
2. | WHERE semantic_description:"What are some easy to prepare but nutritious plant-based meals?"
3. | SORT _score DESC
4. | LIMIT 5
`AI写代码
像 BM25F 这样的词法算法在查询词与文档词语匹配时,能够提供出色的精准性,但当相关内容以不同的方式表达时就会失效。(例如,查询 "athletic footwear " 可能无法找到只写了 "shoes " 或 "trail runner " 的文档。)语义向量搜索使用高维 embedding 和近似最近邻(ANN)算法(例如 HNSW),无论精确词语是否重叠,都能够检索出概念上相似的文档 ------ 但当上下文存在歧义时,也可能引入噪声。
混合搜索如何工作
如果你可以同时获得两者的优势呢?这就是混合搜索。如果实现得当,混合搜索的效果不只是各部分简单相加;它可以产生远优于单独使用词法搜索或语义搜索的结果。混合搜索可以同时提供两者的优势,带来更加均衡的相关性、更高的归一化折损累计增益(NDCG)以及更高的召回率,而无需额外部署第二套搜索系统。
下面是一个混合搜索查询示例:
bash
`
1. GET example-index/_search
2. {
3. "retriever": {
4. "rrf": {
5. "retrievers": [
6. {
7. "standard": {
8. "query": {
9. "term": {
10. "description": "shoes"
11. }
12. }
13. }
14. },
15. {
16. "knn": {
17. "field": "vector",
18. "query_vector": [1.25, 2, 3.5],
19. "k": 50,
20. "num_candidates": 100
21. }
22. }
23. ],
24. "rank_constant": 20,
25. "rank_window_size": 50
26. }
27. }
28. }
`AI写代码
你也可以在 ES|QL 中组合全文搜索和语义查询。在这个示例中,我们使用自定义权重将全文搜索和语义搜索结合起来:
sql
`
1. FROM my-index METADATA _score
2. | FORK ( WHERE match(text_field:"shoes") | SORT _score DESC | LIMIT 50)
3. ( WHERE knn(vector, [1.25, 2, 3.5], { "min_candidates" : 100 }) | SORT _score DESC | LIMIT 50 ) // k for knn is derived from LIMIT
4. | FUSE RRF WITH { "rank_constant": 20 }
5. | SORT _score DESC
6. | LIMIT 50
`AI写代码
执行混合搜索查询通常需要至少执行一次词法搜索和一次语义搜索,然后将它们的结果结合起来。
其中最大的挑战在于如何将多个已排序的结果列表合并成一个统一且连贯的排序结果。
由 BM25F 或 TF-IDF 等算法生成的词法搜索分数可能没有上限,其最大值会受到词频和文档分布的影响。相比之下,语义搜索分数通常位于一个固定范围内,该范围由相似度函数决定(例如,余弦相似度的范围为 0, 2)。
要将它们合并,你需要一种融合方法,在合并过程中保持检索文档之间的相对相关性。
使用 Elasticsearch 进行混合搜索

使用 Elasticsearch 实现混合搜索,可以将标准关键词查询与向量查询结合起来,也可以使用 retriever ------ 一种能够运行多种不同类型的查询,并使用选定的评分方法将它们的结果合并成一个统一排序列表的搜索选项。这样可以在一次搜索调用中实现多阶段检索流程,无需发送多个请求,也无需额外编写客户端逻辑来合并结果。
Elasticsearch 提供了两种内置的融合方法:倒数排名融合(RRF)和线性组合(API 中通常称为 linear retriever)。两者都旨在生成一个统一的排序结果,同时保留各个 retriever 的优势,但它们处理分数的方式不同,最适用的场景也不同。
倒数排名融合完全忽略原始分数,只关注文档在每个列表中的排名位置。排名靠前的文档会获得较高的奖励,而出现在多个列表中的文档会获得累加的 boost。这种方法具有很强的鲁棒性,因为它避开了不同分数范围不兼容的问题,除了 rank 常数之外几乎不需要调优,并且能够自然地提升顶部结果的多样性。
RRF 会根据文档在结果集中的排名对文档进行评分,使用以下公式,其中 k 是一个用于调整低排名文档重要性的任意常数:

RRF 特别适用于不同 retriever 的顶部结果存在一定重叠的场景,以及开发人员需要一种即插即用的解决方案,而不需要带标签的训练数据或复杂的校准。
相比之下,线性组合会直接合并每个 retriever 的实际分数。由于词法搜索和语义搜索的分数处于非常不同的尺度,因此线性组合需要进行归一化,例如使用min-max 缩放,将分数转换到可比较的范围。
完成归一化后,会使用代表每个 retriever 相对重要性的权重对分数进行融合。权重大于 1 会增强某个 retriever 的影响力,而权重小于 1 则会降低其影响力。
这种方法提供了细粒度的控制:当关键词精准性很重要时,开发人员可以提高 BM25F 的权重;当用户意图和上下文至关重要时,可以偏向语义相似度;还可以将额外的业务或个性化信号与检索分数结合起来。当权重经过仔细校准后,线性组合可以通过生成更加准确且可预测的排序结果而优于 RRF,但它确实需要进行实验,并且对特定数据集的调优较为敏感。
线性组合会使用各自的权重以及 β(其中 0 ≤ α、β)来组合词法搜索结果和语义搜索结果,其公式如下:

在实践中,RRF 是混合搜索的最佳起点,因为它简单,并且能够很好地应对不同分数尺度不匹配的问题。它无需大量调优就能产生良好的结果,因此非常适合原型开发或不同 retriever 的结果存在重叠的场景。线性组合则更适合不同检索方法返回互不重叠的结果,或者需要仔细平衡词法、语义和外部信号的场景。简而言之,RRF 可以开箱即用地提供快速、可靠的混合能力,而线性组合在针对具体应用和数据调优权重及归一化器后,则具有更高的潜在准确性。
总结如下:
| 倒数排名融合(RRF) | 线性组合(Linear combination) |
|---|---|
• 即插即用 • 对每个信号进行等权重处理 • 当结果列表存在重叠时效果出色 • 提升顶部结果的多样性 • 只需调节一个参数:rank_constant 从 RRF 开始,可以快速获得稳定的混合搜索结果。 |
• 使用归一化后的分数进行加权融合 • 可以优先考虑业务或个性化信号 • 能很好地处理互不重叠的结果集 • 可以选择归一化器来控制偏差• 提供细粒度的控制 当你准备进一步精细调优相关性时,再转向线性组合。 |
简而言之,线性组合 (linear combination)在经过调优后具有更高的潜在准确性,而 RRF 更容易实现,并且无需带标签的训练数据也能取得良好的效果。
可以通过这个教程进一步了解混合搜索。
混合搜索的检索流程
-
**词汇检索:**BM25F 将查询词与索引中的 token 进行匹配,非常适合精准匹配、结构化过滤以及可解释的评分。
-
**语义检索:**向量(稠密向量或稀疏向量)表示文本的语义;相似度搜索能够找到相关内容,即使它们与查询之间没有共同的词语。
-
**融合:**使用 RRF、加权融合或 linear retriever 将结果进行组合。过滤器和 boost 可以一致地应用于这两种检索方式。
| 搜索类型 | 工作原理 | 结果表现 | 适用场景 |
|---|---|---|---|
| 词法搜索(Lexical search) 查询:"red running shoes size 10" | 将查询中的精确词语与文档中的词语进行匹配(BM25F、TF-IDF、分析器、同义词)。 | 找到标题或描述中包含这些精确 token 的商品,例如:"Nike Men's Red Running Shoes, Size 10"。 | 用户非常明确自己想要什么。精准、可解释且高效。 |
| 语义搜索(Semantic search) 查询:"lightweight shoes for jogging" | 使用 embedding 捕捉语义和上下文,而不仅仅是关键词。即使词语不匹配,也能找到概念上相关的结果。 | 可以返回"Adidas Cloudfoam Running Sneakers, Size 10",即使其中没有直接出现"lightweight"和"jogging"。 | 用户通过自然语言描述自己的意图。适合模糊或描述性的查询。 |
| 混合搜索(Hybrid search) 查询:"comfortable dress shoes for office" | 结合词法和语义搜索结果,然后融合它们的排序(例如使用 RRF)。 | 同时检索精确匹配的结果,例如"Black Leather Dress Shoes, Comfort Fit ",以及语义相关的结果,例如"Loafers with cushioned insoles",并按照相关性统一排序。 | 查询同时包含精确条件和用户意图。能够在准确性与探索能力之间取得平衡。 |
深入了解混合搜索:解析稠密向量和稀疏向量
Elasticsearch 中的语义搜索通过将查询和文档转换为能够捕捉语义的向量表示来实现。混合搜索将词法检索与语义检索结合起来,而语义检索既可以使用稠密模型,也可以使用稀疏模型。
稠密向量
稠密向量是由 BERT 等模型生成的固定长度数字数组,其中语义相似的输入(例如 cat 和 kitten)在向量空间中的距离更近,因此非常适合语义匹配、推荐和相似度搜索。
当文本被转换为稠密向量后,其形式如下:
markdown
`
1. [
2. 0.13586345314979553,
3. -0.6291824579238892,
4. 0.32779985666275024,
5. 0.36690405011177063,
6. ...
7. ]
`AI写代码
每个维度都包含有意义的信息,使得向量中充满数据。语义相似的内容会生成在向量空间中彼此接近的 embedding。
在 Elasticsearch 中,稠密向量存储在 dense_vector 字段中,并使用 HNSW 等近似最近邻(ANN)算法进行查询。这非常适合捕捉文本、图像或其他内容的整体语义。
bash
`
1. POST my-index/_search
2. {
3. "retriever": {
4. "rrf": {
5. "retrievers": [
6. {
7. "standard": {
8. "query": {
9. "match": {
10. "text_field": "fox"
11. }
12. }
13. }
14. },
15. {
16. "knn": {
17. "field": "title_vector",
18. "query_vector": [0.1, 3.2, 2.1],
19. "k": 5,
20. "num_candidates": 100
21. }
22. }
23. ]
24. }
25. }
26. }
`AI写代码
下面是一个 ES|QL 示例:
sql
`
1. FROM my-index METADATA _score
2. | FORK ( WHERE match(text_field:"fox") | SORT _score DESC | LIMIT 5)
3. ( WHERE knn(image_vector, [0.1, 3.2, 2.1], { "min_candidates" : 100 }) | SORT _score DESC | LIMIT 5 )
4. | FUSE
5. | SORT _score DESC
`AI写代码
如上所示,一个混合搜索查询只需使用 rrf retriever,将通过标准 retriever 执行的词法搜索查询(例如 match 查询)与 knn retriever 中指定的向量搜索查询结合起来即可。
该查询首先在全局范围内检索排名前五的向量匹配结果,然后将它们与词法搜索匹配结果进行融合,最后返回最匹配的 10 个结果。
rrf retriever 使用 RRF 排名方法来融合向量搜索和词法搜索的匹配结果。
理解稀疏向量和 ELSER
稠密 embedding 并不是实现语义搜索的唯一方式。
稀疏向量大部分维度都是零,只有少数带权重的值与可解释的词语相关联,因此具有资源效率高、可解释性强以及在 zero-shot 场景下效果良好等特点。
稀疏向量的表示形式如下:
json
`{"f1":1.2,"f2":0.3,...}` AI写代码
在 Elasticsearch 中,Elastic Learned Sparse EncodeR(ELSER)是一种域外稀疏自然语言处理(NLP)模型,它会将文本扩展为语义相关的词语并为这些词语分配权重,从而在保留可解释性的同时,实现超越精确关键词匹配的搜索。
此外,semantic_text 字段让语义搜索像传统文本搜索一样简单,因为它会在 ingest 时自动处理 embedding 生成和推理。你可以像索引 text 字段一样索引文档,然后执行一个简单的 match 查询------即使跨索引查询时字段类型不同,也可以同时获得词法和语义匹配,而无需额外的查询逻辑。对于更高级的控制,可以在同一字段上使用 knn 或 sparse_vector 查询。
使用 ELSER 的示例:
-
基于约 30,000 个词语的词汇表进行预训练
-
以
sparse_vector(词语/权重对)的形式存储 -
在 ingest 时通过
semantic_text自动生成,或者在索引时通过 inference ingest processor 生成 -
通过倒排索引进行查询(类似词法搜索),因此具有高效、易于过滤且可解释等特点
bash
`
1. POST my-index/_search
2. {
3. "retriever": {
4. "rrf": {
5. "retrievers": [
6. {
7. "standard": {
8. "query": {
9. "match": {
10. "text_field": "fox"
11. }
12. }
13. }
14. },
15. {
16. "standard": {
17. "query": {
18. "sparse_vector": {
19. "field": "ml.tokens",
20. "inference_id": ".elser_model_1",
21. "query": "a quick brown fox jumps over a lazy dog"
22. }
23. }
24. }
25. }
26. ]
27. }
28. }
29. }
`AI写代码
稠密向量和稀疏向量结合起来可以提供更大的灵活性:稠密向量擅长捕捉细微的语义,而稀疏向量则能够为实际生产环境中的搜索提供更高的透明度和可扩展性。
了解使用 ELSER 进行文本扩展如何帮助你获得更好的搜索结果:
www.bilibili.com/video/BV1R3...
实际应用中的稀疏向量与稠密向量
| 稀疏向量(ELSER) | 稠密向量 | |
|---|---|---|
| 工作原理 | 将文本扩展为语义相关的、带权重的词语。每个维度对应一个 token,并带有相应的权重。 | 将内容(文本、图像等)编码为固定长度的浮点向量。语义越相似,在向量空间中的位置越接近。 |
| 优势 | • 结果可解释(词语 + 权重)• 与关键词相关性自然结合• 非常适合领域特定词汇 | • 能够捕捉深层语义• 支持多模态(文本、图像、音频)• 擅长自然语言和相似度匹配 |
| 典型使用场景 | • 通过文本扩展增强关键词搜索• 对合规和审计友好的企业搜索• 技术或受监管领域的专业搜索 | • 将自然语言问题与答案进行匹配• 图像或多媒体相似度搜索• 基于内容的推荐 |
| 理想场景 | 当你需要提升语义能力和透明度,或者领域特定词语最重要时 | 当你需要捕捉深层语义、自然语言意图或跨模态相似性时 |
使用稠密和稀疏模型进行混合搜索
到目前为止,我们已经了解了两种不同的混合搜索方式,具体取决于搜索的是稠密向量空间还是稀疏向量空间。我们也可以在同一个索引中同时混合稠密数据和稀疏数据。
bash
`
1. POST my-index/_search
2. {
3. "_source": false,
4. "fields": [ "text_field" ],
5. "retriever": {
6. "rrf": {
7. "retrievers": [
8. {
9. "knn": {
10. "field": "image_vector",
11. "query_vector": [0.1, 3.2, ..., 2.1],
12. "k": 5,
13. "num_candidates": 100
14. }
15. },
16. {
17. "standard": {
18. "query": {
19. "sparse_vector": {
20. "field": "ml.tokens",
21. "inference_id": ".elser_model_1",
22. "query": "a quick brown fox jumps over a lazy dog"
23. }
24. }
25. }
26. }
27. ]
28. }
29. }
30. }
`AI写代码
进一步探索:结合稠密向量、稀疏向量和 BM25F 的混合搜索
这个示例结合了三种 retriever,并使用 RRF 融合它们的排序列表:
-
**BM25F(在
text上执行match):**精准匹配关键词或短语,例如"snowy mountain" -
**kNN(
image_vector):**使用提供的图像 embedding 进行视觉相似度搜索,从num_candidates中获取 k 个结果 -
**Semantic(
semantic_text):**通过对查询进行语义扩展来匹配概念
rank_window_size 控制参与融合的结果数量;rank_constant 用于平衡每个结果列表的贡献。
bash
`
1. GET my-index/_search
2. {
3. "retriever": {
4. "rrf": {
5. "retrievers": [
6. {
7. "standard": {
8. "query": {
9. "match": {
10. "text": {
11. "query": "snowy mountain"
12. }
13. }
14. }
15. }
16. },
17. {
18. "knn": {
19. "field": "image_vector",
20. "query_vector": [
21. 0.01,
22. 0.3,
23. -0.4
24. ],
25. "k": 10,
26. "num_candidates": 100
27. }
28. },
29. {
30. "standard": {
31. "query": {
32. "semantic": {
33. "field": "semantic_text",
34. "query": "snowy mountain"
35. }
36. }
37. }
38. }
39. ],
40. "rank_window_size": 50,
41. "rank_constant": 60
42. }
43. }
44. }
`AI写代码
让我们再来看一个类似的 ES|QL 示例:
sql
`
1. FROM my-index METADATA _score
2. | FORK (WHERE match(text, "snowy mountain") | SORT _score DESC | LIMIT 50)
3. (WHERE knn(image_vector, [0.01, 0.3, -0.4], {"min_candidates": 100 }) | SORT _score DESC | LIMIT 50)
4. (WHERE match(semantic_text, "snowy mountain") | SORT _score DESC | LIMIT 50)
5. | FUSE RRF WITH {"rank_constant": 60 } // 60 is the default anyway?
6. | SORT _score DESC
7. | LIMIT 50
`AI写代码
总结
混合搜索将全文搜索的精准性与语义搜索的上下文理解能力结合起来,从而能够针对不同类型的内容提供更加准确、相关的结果。通过同时支持稠密和稀疏模型,以及线性组合和倒数排名融合等灵活的融合方法,你可以根据具体使用场景定制检索方式------无论是直接组合查询和向量,还是使用 retriever 简化多阶段检索。这种灵活性使混合搜索成为处理复杂查询、多样化数据以及高相关性要求的强大方法。
进一步了解混合搜索:
-
阅读这篇博客,了解什么是混合搜索、Elasticsearch 支持哪些查询类型,以及如何构建混合搜索。
想要超越向量搜索?可以了解 Elasticsearch 中的使用 LLM agents 实现智能混合搜索。
准备动手实践了吗?可以按照我们的混合搜索教程,将全文搜索和 kNN 结果结合起来;或者尝试ES|QL 教程,使用 ES|QL 进行搜索和过滤。
原文:What is hybrid search? How it works and when to use it | Elastic