Skip to content

搜索引擎 架构模板

代表产品:Google、Bing、Elasticsearch、电商 / 站内搜索 一句话定位:把海量文档预先「翻过来」建成倒排索引,让任意关键词都能在毫秒内找到最相关的结果并排好序。


1. 一句话定位

搜索引擎 = 一个离线慢慢「建索引」的世界 + 一个在线毫秒级「查索引」的世界

它最核心的智慧是一句话:把工作量从「查询时」挪到「索引时」。 用户查询时之所以能在几十毫秒内从十亿文档里找出答案,是因为系统早就离线把数据翻来覆去整理好了。理解搜索引擎,就是理解这种「用预处理换实时性」的交易。

2. 业务本质:它在解决什么问题

人类面对的信息量远超能处理的极限。搜索引擎解决的是「从海量内容里,把最相关的几条快速捞到你眼前」——它把「大海捞针」变成「秒级精准命中」。

钱从哪来:搜索结果旁的广告(搜索意图 = 最值钱的广告场景)、企业 / 站内搜索的授权、电商搜索的导流与排序。

一个反直觉的事实:搜索引擎技术再强,搜不准也等于没用。 它的产品价值有一半在「相关性」这个没有标准答案、需要持续调优的软指标上。

3. 核心需求与约束

功能性需求:

  • [ ] 全文检索:输入关键词,找出包含它的文档
  • [ ] 相关性排序:最该看的排最前
  • [ ] 分词 / 自动补全 / 拼写纠错
  • [ ] 过滤与分面(按价格、类别等维度筛选 / 聚合)
  • [ ] 索引更新:新内容能被搜到

非功能性需求 / 质量属性:

质量属性目标为什么对这类系统重要
查询延迟< 几百 ms搜索是即时交互,慢了就走
相关性越准越好产品的灵魂,直接决定好不好用
索引新鲜度秒级~分钟级新内容多久能被搜到
规模十亿级文档索引和查询都海量

关键约束(不可逾越的边界):

  • 🔴 文档海量,查询更海量:两个负载形态完全不同,必须分开设计。
  • 🔴 相关性没有标准答案:它是主观的、需要不断用数据调优的,不像「1+1=2」。
  • 🔴 不能实时扫描原文:十亿文档逐个 LIKE '%关键词%' 扫一遍,等到天黑也出不来——必须预先建索引。

4. 架构全景图

═══════════ 离线:建索引(慢工出细活)═══════════
   ┌────────┐   ┌──────────────┐   ┌──────────────┐
   │ 爬虫 /  │──▶│ 文档处理      │──▶│ 索引构建      │
   │ 数据源  │   │ 分词/归一化   │   │ 生成倒排索引  │
   └────────┘   └──────────────┘   └──────┬───────┘

                              ┌────────────────────────┐
                              │  倒排索引(分片 + 副本)   │
                              │  词 →「含它的文档列表」   │
                              └────────────┬───────────┘
═══════════ 在线:查索引(快字当头)═══════════    │
   ┌────────┐   ┌──────────────┐   ┌──────────▼─────────┐
   │ 用户    │──▶│ 查询解析      │──▶│ ① 召回:从各分片快速  │
   │ 查询    │   │ 分词/纠错/补全 │   │   捞出候选(广而粗)  │
   └────────┘   └──────────────┘   │ ② 精排:对候选精细打分│
        ▲                          │   (准而细)          │
        └──────── 排好序的结果 ◀────┴────────────────────┘

灵魂是中间那座倒排索引:它是离线世界「预先组织好的成果」,也是在线世界「毫秒响应的底气」。整个架构就是「离线建它、在线查它」两件事。

5. 组件职责

  • 爬虫 / 数据接入:抓取或接收要被搜索的文档。为什么需要:索引的原料来源。
  • 文档处理 / 分词:把文档拆成词项、统一大小写 / 词形、去停用词。为什么需要:搜索的基本单位是「词」,必须先把文本切成词。
  • 索引构建:把「文档 → 词」翻转成「词 → 文档列表」的倒排索引。为什么需要:这是「把工作挪到索引时」的核心动作。
  • 倒排索引存储(分片 + 副本):海量索引切片存储,副本扛查询量。为什么需要:十亿文档一台机器放不下、也扛不住查询。
  • 查询服务:解析查询、纠错、补全,扇出到各分片召回,再归并。为什么需要:在线查询的入口与协调者。
  • 排序 / 打分:决定结果先后。先用关键词匹配粗排(召回),再用更复杂的模型精排。为什么需要:相关性是产品价值所在。

6. 关键数据流

场景一:建立索引(离线,把工作提前做掉)

1. 爬虫抓到文档「架构思维很重要」
2. 分词 ──▶ [架构, 思维, 重要]
3. 写入倒排索引:
      "架构" → [文档7, 文档12, 文档99, ...]
      "思维" → [文档3, 文档7, ...]
   (注意:存的是「词指向哪些文档」,不是「文档包含哪些词」)

场景二:一次查询(在线,召回 + 精排两阶段)

1. 用户搜「架构 思维」──▶ 查询解析、分词、纠错
2. ① 召回:在各分片查倒排表,取「架构」和「思维」文档列表的交集
        ──▶ 几千个候选(快、广、粗)
3. ② 精排:只对这几千个候选算精细相关性分数(关键词权重、新鲜度、个性化…)
        ──▶ 排出前 10(慢、准,但只对少量算)
4. 归并各分片结果,返回排好序的前 10 条

关键是第 2、3 步的漏斗:绝不可能对十亿文档逐个精排(算不过来),而是「先粗筛出候选,再精细排少量」。

7. 数据模型与存储选择

核心结构:倒排索引(词 → 文档列表 + 位置 + 词频);正排(文档 → 各字段值,用于展示和过滤);原文

数据存储类型为什么
倒排索引专用搜索引擎存储(分片)为「按词查文档」这种访问形态量身打造
正排 / 文档字段列存 / KV取回展示字段、做分面聚合
原始文档对象存储大、不变、按 ID 取回
热门查询结果缓存头部查询高度集中,缓存收益大

教学点:倒排索引就是「为『按词查文档』这个问题,预先把数据组织成最趁手的形状」。 用关系型数据库的 LIKE 做全文搜索,等于拿错了工具——它没有为这个问题组织过数据。

8. 关键架构决策与权衡 ⭐

决策 1:倒排索引,还是直接扫描?(搜索的立身之本)⭐

  • 顺序扫描(LIKE '%词%'):无需预处理,但每次查询都要扫全部文档,十亿级根本不可行,且无法做相关性排序。
  • 倒排索引:离线把「词 → 文档」建好,查询时直接命中。
  • 取向:必然选倒排。代价是索引要占额外存储、且写入(建索引)变重变慢——这正是「拿写时的代价,换读时的飞快」。

决策 2:索引怎么分片?按文档分,还是按词分?

  • 按文档分(每个分片存一部分文档的完整索引):查询要扇出到所有分片再归并(scatter-gather),但写入简单、扩展自然。
  • 按词分(每个分片存一部分词的全部文档列表):查询可能只问几个分片,但写入和热点词处理复杂。
  • 取向:绝大多数选按文档分片,简单、易扩,代价是每次查询都得问所有分片(尾延迟受最慢分片拖累)。

决策 3:召回 + 精排的两阶段架构 ⭐

  • 一步到位精排:对所有匹配文档都算复杂分数——量大就算爆了。
  • 两阶段:先用轻量方式召回海量候选,再用重模型精排少量。
  • 取向:几乎所有大搜索都是两阶段漏斗。这个「先粗后精」的思想,在推荐、风控里同样通用。

决策 4:索引新鲜度——多实时?

  • 全量重建:简单,但新内容要等下一轮才搜得到。
  • 近实时增量:新文档很快进入索引,但实现复杂、有资源开销。
  • 取向:多数场景近实时(秒级~分钟级)足够,别为「绝对实时」付出不成比例的代价。

9. 规模化与瓶颈

  • 第一个瓶颈:文档增长,单机索引放不下。 → 破解:索引分片(按文档切),加副本扛读。
  • 第二个瓶颈:查询量增长。 → 破解:查询节点水平扩 + 副本 + 缓存头部热门查询。
  • 第三个瓶颈:scatter-gather 的尾延迟(查询要等最慢的那个分片)。→ 破解:控制分片数、副本择优、超时降级(少一个分片的结果也先返回)。
  • 第四个瓶颈:索引更新和查询争抢资源。 → 破解:读写分离,在副本上查询、在另一处构建,建好再切换。

10. 安全与合规要点

  • 爬取合规:尊重 robots、版权与抓取频率,别把别人站爬挂。
  • 查询隐私:搜索词极度暴露意图与隐私,要严格保护、脱敏、限制留存。
  • 权限过滤(企业搜索关键):用户只能搜到自己有权限的文档——权限过滤要在召回阶段就生效,不能「先搜出来再隐藏」(否则可由结果数推断出存在)。
  • 查询注入:对查询语法做转义,防止构造恶意查询拖垮系统或越权。

11. 常见误区 / 反模式

  • 用数据库 LIKE '%x%' 做全文搜索 → ✅ 倒排索引,这是全文检索的正道。
  • 索引时和查询时不分离,互相拖累 → ✅ 离线建、在线查,读写分开。
  • 一步到位对所有文档精排 → ✅ 召回 + 精排两阶段漏斗。
  • 追求 100% 实时索引 → ✅ 近实时通常足够,别过度付费。
  • 只堆技术不调相关性 → ✅ 持续用点击 / 反馈数据调排序,搜得准才有用。
  • 企业搜索先搜后隐藏 → ✅ 权限过滤要在召回阶段就介入。

12. 演进路线:MVP → 成长期 → 成熟期

阶段规模量级架构长什么样此时该操心什么
MVP百万级文档直接用现成搜索引擎,单机或少量节点,基础分词 + 关键词排序先把「能搜到、还算准」跑起来
成长期千万~亿级索引分片 + 副本、近实时更新、自动补全 / 纠错、相关性初步调优查询延迟、相关性、索引新鲜度
成熟期十亿级 + 个性化召回 + 机器学习精排(LTR)、查询理解、个性化、多语言、分布式大规模索引相关性持续优化、规模、成本、体验

13. 可复用要点

  • 💡 「把工作从查询时挪到写入 / 索引时」是一切读优化的本质。 缓存、物化视图、预计算、倒排索引,都是同一个思想的变体。
  • 💡 召回 + 精排的两阶段漏斗,是处理「海量候选里挑少数」的通用范式。 推荐系统、风控、广告投放都用它。
  • 💡 特殊的查询形态,需要专门组织的数据结构。 全文检索要倒排索引,正如地理查询要空间索引——别用通用工具硬扛特殊问题。
  • 💡 scatter-gather(扇出 - 归并) 是分布式查询的常见骨架,它的代价永远是「等最慢的那个分片」。

🎯 随堂检验

🤔搜索引擎能在海量文档里毫秒级返回,根本原因是?
  • A查询时实时扫描所有文档
  • B离线预先把数据建成倒排索引
  • C机器够快

参考原型与延伸阅读

本模板基于以下真实开源项目官方工程博客整理。

🔧 开源原型(可直接读代码):

  • apache/lucene — 全文检索内核(Solr / Elasticsearch / OpenSearch 的底层),倒排索引 + 不可变 segment 的标准实现。
  • quickwit-oss/tantivy — 受 Lucene 启发的 Rust 全文检索库,适合理解倒排索引与检索引擎底层。

📖 工程博客:


📌 一句话记住搜索引擎:它不是「在线翻遍所有文档」,而是「离线把数据翻来覆去整理好,在线只需查一张早就备好的索引」——所有设计都在回答『怎么用预处理,换来查询时的毫秒级精准』。