# Manticore Search中的混合搜索

使用RRF在Manticore中结合全文搜索和向量搜索，以获得比单独使用任一方法更精确的结果

搜索很少是一个一刀切的问题。输入"cheap running shoes"的用户想要精确的关键词匹配，而询问"comfortable footwear for jogging"的用户则用不同的词语表达相同的意图。传统的全文搜索处理第一种情况很有效。向量搜索处理第二种情况。混合搜索将两者结合到一个查询中，因此无需选择。

在现代搜索系统中，这通常被描述为结合**词法（稀疏）检索**与**语义（密集）检索**。不同的术语，相同的理念：精确匹配加上含义。

## 什么是混合搜索？

混合搜索并行运行全文（BM25）搜索和向量（KNN）搜索，然后将两个结果列表合并为一个。在任一信号（或两者）上得分高的文档会排在前面。

全文搜索擅长精确关键词、罕见术语和标识符。向量搜索理解含义——"automobile"和"car"是相同概念，因为它们的嵌入在向量空间中相近。

每种方法都有盲点：
- 全文搜索在同义词和自然语言上存在困难
- 向量搜索在精确的标记如SKU、错误代码和ID上存在困难

混合搜索覆盖了两者。

## 混合搜索如何融入现代搜索流程

混合搜索是**检索阶段**——从数据集中找到相关候选的部分。

与其依赖单一方法，混合搜索结合关键词匹配和语义相似性，从一开始就生成更强的结果集。

实际上这意味着：
- 自然语言查询的更好召回率
- 对SKU或错误代码等标识符的精确匹配
- 无需复杂查询逻辑即可获得更相关的结果

目标很简单：使用两种信号一起，在单次传递中返回最佳可能的候选。

## 何时应该使用它？

混合搜索适合以下情况：

- 查询混合意图和具体细节。像`python error 403 forbidden`这样的搜索可以从错误代码的精确匹配和问题描述的语义理解中受益。
- 你正在构建RAG管道。检索增强生成需要将最相关的块传递给LLM。混合检索比单独使用任一方法更一致地找到更多相关文档。
- 你的目录包含结构化和非结构化数据。电子商务产品有精确的名称和型号（关键词领域），但也有描述，其中含义比精确措辞更重要。
- 你无法预测用户如何搜索。一些人会粘贴精确短语，其他人会用自然语言描述他们寻找的内容。混合搜索都能优雅处理。

## 它如何工作

Manticore使用倒数排名融合（RRF）来合并结果。这个想法很简单：与其尝试将原始BM25分数与KNN距离进行比较（它们的尺度完全不同），RRF查看排名位置。在文本结果中排名第一，在KNN结果中排名第三的文档，其综合得分高于只出现在一个列表中的文档。

这里有一个快速示例。假设文本搜索和KNN搜索各自返回自己的前三名：

文本搜索结果：

| 排名 | 文档 |
|------|----------|
| 1 | 文档A |
| 2 | 文档B |
| 3 | 文档C |

KNN搜索结果：

| 排名 | 文档 |
|------|----------|
| 1 | 文档C |
| 2 | 文档A |
| 3 | 文档D |

RRF使用公式`1 / (rank_constant + rank)`为每个文档评分。使用默认的`rank_constant=60`：

| 文档 | 文本贡献 | KNN贡献 | RRF得分 |
|---|---|---|---|
| 文档A | 1/(60+1) = 0.0164 | 1/(60+2) = 0.0161 | 0.0325 |
| 文档C | 1/(60+3) = 0.0159 | 1/(60+1) = 0.0164 | 0.0323 |
| 文档B | 1/(60+2) = 0.0161 | — | 0.0161 |
| 文档D | — | 1/(60+3) = 0.0159 | 0.0159 |

文档A排名第一，因为它在两个列表中都接近顶部。文档C紧随其后，原因相同。文档B和文档D只出现在一个列表中，因此得分较低。

### 为什么使用RRF？

结合结果有两种常见方式：

- **基于排名的融合（RRF）**——简单、稳健，无需标准化分数
- **基于分数的融合**——先标准化分数，然后结合

Manticore使用RRF，因为它开箱即用效果良好，并避免了分数校准问题。

在底层，混合查询被拆分为独立的子查询——一个用于全文，一个（或多个）用于KNN——并行运行。所有子查询完成后，RRF将它们的排名结果列表融合成一个输出。

## 为什么不用其中一种？

考虑一个包含不同错误代码文章的支持知识库——连接失败、认证问题、同步问题。用户在屏幕上看到错误E-5020并报告："我无法连接到服务器。"

向量搜索理解症状但不理解错误代码。对"can not connect to the server"的KNN搜索返回：

| # | 标题 | KNN距离 |
|---|-------|-------------|
| 1 | 错误E-5030：DNS解析失败 | 0.572 |
| 2 | 错误E-2091：应用加载超时 | 0.583 |
| 3 | 错误E-5020：SSL证书不匹配 | 0.605 |
| 4 | 错误E-5010：服务不可用 | 0.622 |
| 5 | 错误E-4001：登录失败 | 0.665 |

正确的文章（E-5020）被埋在第3位。KNN将DNS和超时错误排名更高，因为它们的描述在语义上更接近"无法连接"。实际问题——SSL证书不匹配——使用完全不同的词汇，因此得分较低。

你可能会想：只需将错误代码添加到KNN查询中。但"E-5020"和"E-5010"是任意标识符，没有语义意义——嵌入将它们视为几乎相同的标记。对"E-5020 can not connect to the server"的KNN搜索确实将E-5020移到第1位，但只是因为添加的文本改变了语义上下文——错误代码本身没有权重。

混合搜索通过将每个信号发送到它最有效的地方来解决这个问题——将错误代码发送到全文搜索，将症状发送到KNN：

```sql
SELECT title, hybrid_score()
FROM support_articles
WHERE knn(embedding, 'can not connect to the server')
  AND MATCH('E-5020')
LIMIT 5
OPTION fusion_method='rrf';
```

| # | 标题 | 混合得分 |
|---|-------|-------------|
| 1 | 错误 E-5020: SSL 证书不匹配 | 0.032 |
| 2 | 错误 E-5030: DNS 解析失败 | 0.016 |
| 3 | 错误 E-2091: 应用加载超时 | 0.016 |
| 4 | 错误 E-5010: 服务不可用 | 0.016 |
| 5 | 错误 E-4001: 登录失败 | 0.015 |

E-5020 从 #3 跳跃到 #1，其得分是其他所有项的两倍。全文搜索将 "E-5020" 视为精确字符串——不与 "E-5010" 相似，也不足够接近，只是不同。KNN 确保相关连接错误仍会出现在下方以提供上下文。

这是混合搜索的核心价值：

- 标识符 → 全文搜索
- 含义 → 向量搜索

每种方法都能覆盖另一种的盲点。

## 入门

运行混合搜索最简单的方式是使用 `hybrid_match()`。如果您的表已配置自动嵌入，一行代码即可完成所有操作——文本搜索、嵌入生成、KNN 搜索和 RRF 融合：

```sql
SELECT id, hybrid_score()
FROM products
WHERE hybrid_match('running shoes');
```

等效的 JSON 表达式：

```json
POST /search
{
  "table": "products",
  "hybrid": { "query": "running shoes" }
}
```

Manticore：
- 生成嵌入
- 并行运行两种搜索
- 融合结果

### 完全控制：显式 MATCH + KNN

当您需要提供自己的向量或调整单个子查询时，请使用 WHERE 子句中的显式形式 `MATCH()` 和 `KNN()`：

```sql
SELECT id, hybrid_score()
FROM products
WHERE match('running shoes')
  AND knn(embedding, (0.12, 0.45, 0.78, ...))
OPTION fusion_method='rrf';
```

```json
POST /search
{
  "table": "products",
  "knn": {
    "field": "embedding",
    "query_vector": [0.12, 0.45, 0.78, "..."]
  },
  "query": { "match": { "title": "running shoes" } },
  "options": { "fusion_method": "rrf" }
}
```

每个结果包括：
- `hybrid_score()` — 融合得分（用于默认排序）
- `weight()` — BM25 得分
- `knn_dist()` — 向量距离

属性过滤器（`AND category = 'footwear'`）适用于两个子查询。

## 调整

三个选项可让您调整融合行为：

- `rank_constant` — 控制排名位置在融合得分中的主导程度。较低的值（例如 10）会使排名 #1 的重要性显著高于排名 #5。较高的值会平滑曲线。参见 [rank_constant](https://manual.manticoresearch.com/Searching/Options#rank_constant)。
- `fusion_weights` — 允许您为每个子查询分配不同的重要性。如果文本相关性比向量相似性更重要，请提高其权重。参见 [fusion_weights](https://manual.manticoresearch.com/Searching/Options#fusion_weights)。
- `window_size` — 每个子查询在融合前检索的结果数量。默认情况下，Manticore 会根据您的 KNN 参数和查询 LIMIT 自动计算此值。参见 [window_size](https://manual.manticoresearch.com/Searching/Options#window_size)。

## 多向量融合

混合搜索不限于一个文本搜索加一个 KNN 搜索。您可以将多个向量搜索融合在一起——当您的数据具有多个不同的语义维度时非常有用。例如，电子商务产品有文本描述和照片。用户搜索 "极简白色运动鞋" 时，两者都很重要：标题应匹配风格，产品图片应与用户脑海中所想相似。通过将标题和图片分别编码到不同的向量空间中，您可以同时搜索两者，并让 RRF 展示在所有三个信号（关键词、文本含义和视觉相似性）上都匹配的产品：

```sql
SELECT id, hybrid_score()
FROM products
WHERE match('running shoes') AS text
  AND knn(title_vec, (0.12, 0.45, ...)) AS title_sim
  AND knn(image_vec, (0.88, 0.21, ...)) AS image_sim
OPTION fusion_method='rrf',
       fusion_weights=(text=0.5, title_sim=0.3, image_sim=0.2);
```

所有子查询并行运行，并通过 RRF 融合在一起。

## 结论

混合搜索不是为了取代全文搜索或向量搜索——而是为了在它们表现最佳的地方同时使用两者。

关键词搜索为您提供精确的术语和标识符匹配。向量搜索为您提供自然语言和含义的灵活性。单独使用时，每种方法都有其局限性。结合使用时，它们在各种查询中都能产生更一致的结果。

在 Manticore 的混合搜索中，您无需在两者之间做出选择，也无需构建复杂的查询逻辑来处理不同情况。您可以并行运行两种信号，并获得一个统一的结果集。

如果您的搜索需要同时处理精确匹配和意图——这在大多数实际应用中都是如此——混合搜索是一种无需增加复杂性即可提高相关性的直接方法。
