Skip to content

概念

搜索:用户有明确意图,输入关键词,系统返回相关结果。核心是相关性

推荐:用户没有明确意图,系统根据用户行为和偏好主动推送内容。核心是个性化


核心原理

1. 搜索引擎架构(Elasticsearch)

集群架构

概念说明
Cluster一组节点组成的集群,共同对外提供服务
Node单个 ES 实例,可承担 Master / Data / Coordinating 角色
Index逻辑上的数据集合,类似关系型数据库中的表
ShardIndex 的物理分片,数据水平拆分到多个节点
Replica分片的副本,提供高可用和读扩展能力

倒排索引(Inverted Index)

倒排索引是搜索速度快的根本原因。建立时将文档中的词项(Term)映射到包含该词项的文档列表。

词项        → 文档列表(DocID + 位置)
"手机"      → [doc1(pos:3), doc5(pos:1), doc9(pos:7)]
"华为"      → [doc1(pos:1), doc3(pos:4)]
"5G"        → [doc1(pos:5), doc5(pos:3)]

查询时直接查词项表,取交集/并集,时间复杂度远低于全表扫描。

文档写入流程

客户端写入

Coordinating Node(路由计算:shard = hash(doc_id) % primary_shards)

Primary Shard(写入 In-memory buffer + Translog)

refresh(默认 1s)→ 生成 Segment,文档变为可搜索状态(Near Real-Time)

flush → Segment 持久化到磁盘,Translog 清空

Replica Shard(同步复制)

近实时搜索(NRT)refresh_interval 默认 1 秒,新写入的文档最多延迟 1 秒可被搜索到。写入压力大时可调大该值(如 30s)以提升吞吐。


2. 搜索优化

相关性评分

  • TF-IDF:词频(TF)越高、逆文档频率(IDF)越高,得分越高。IDF 体现词的区分度("的"这种高频词 IDF 很低)。
  • BM25(ES 默认):TF-IDF 的改进版,对高词频做饱和处理,加入文档长度归一化,结果更稳定。

多字段搜索与权重提升

json
{
  "multi_match": {
    "query": "华为手机",
    "fields": ["title^3", "description^1", "brand^2"],
    "type": "best_fields"
  }
}

^3 表示 title 字段权重是 description 的 3 倍。

分析器与分词器

场景分析器
英文标准分词standard
中文分词ik_max_word(细粒度)/ ik_smart(粗粒度)
拼音搜索pinyin analyzer
精确匹配keyword(不分词)

自动补全(Auto-Complete):使用 completion 字段类型 + suggest API,响应速度 < 10ms。

模糊搜索(Fuzzy Search)fuzziness: "AUTO" 允许一定编辑距离,处理拼写错误。

高亮(Highlight):返回结果中标记命中词项,提升用户体验。


3. 搜索基础设施

索引设计(Mapping)

json
{
  "mappings": {
    "properties": {
      "title":       { "type": "text", "analyzer": "ik_max_word", "boost": 3 },
      "price":       { "type": "double" },
      "category_id": { "type": "keyword" },
      "created_at":  { "type": "date" },
      "tags":        { "type": "keyword" }
    }
  }
}
  • text:全文检索,需要分词
  • keyword:精确匹配、聚合、排序
  • 字段一旦创建类型不可更改,需要 reindex

分片策略

  • 单个分片建议保持在 10–50 GB
  • 分片数 = 预估数据量 / 单分片目标大小
  • 分片数确定后不可修改(需提前规划),副本数可动态调整

冷热数据分层(ILM)

Hot(高性能 SSD)→ Warm(普通 HDD)→ Cold(对象存储)→ Delete
    写入/查询         只读/压缩          归档/低频           自动删除

数据同步:MySQL → ES

MySQL(业务数据库)
    ↓ binlog
Canal(监听 binlog,解析变更事件)

Kafka(消息队列,削峰解耦)

Consumer(消费消息,调用 ES Bulk API)

Elasticsearch(搜索索引)
  • Canal 伪装成 MySQL 从节点,实时捕获 binlog
  • Kafka 保证消息不丢失,支持重放
  • 消费端做幂等处理(以主键为文档 ID,upsert 操作)

4. 推荐系统架构:四阶段 Pipeline

海量候选集(千万级)
        |
  [召回 Recall]        — 多路策略快速筛选,候选集 → 千级
        |
  [粗排 Pre-Rank]      — 简单模型快速打分,千级 → 百级
        |
  [精排 Rank]          — 复杂深度模型精细打分,百级 → 十级
        |
  [重排 Re-Rank]       — 去重、多样性、业务干预,十级 → 最终结果
        |
    用户 Feed
阶段目标典型技术
召回从海量内容中快速捞出相关候选协同过滤、向量检索(ANN)、倒排索引
粗排快速过滤低质候选,降低精排压力LR、GBDT、简单 DNN
精排精细化排序,最大化点击/转化Wide & Deep、DeepFM、Transformer
重排业务规则、多样性、打散、广告插入MMR 算法、规则引擎

5. 召回策略

协同过滤(Collaborative Filtering)

  • UserCF:找到兴趣相似的用户,推荐他们喜欢但当前用户未看过的内容
    • 适合用户量小、社交场景
  • ItemCF:找到与用户历史行为物品相似的物品推荐
    • 适合物品量小、电商场景,结果可解释性强

基于内容(Content-Based):提取物品特征(标签、类目、作者),与用户历史偏好匹配。

热门/新品兜底:解决冷启动,对新用户推送热门内容;对新物品推送给相关用户群体测试。

多路召回(Multi-Channel Recall)

UserCF 召回 ──┐
ItemCF 召回 ──┤
向量召回    ──┼──→ 合并去重 → 粗排
热门召回    ──┤
新品召回    ──┘

多路并行,各路召回互补,提高覆盖率和多样性。


6. 特征工程

特征类别示例
用户特征年龄、性别、城市、历史点击、兴趣标签
物品特征类目、标签、发布时间、热度、质量分
上下文特征当前时间、设备类型、网络环境、地理位置
实时特征过去 1 小时点击率、当前会话行为序列

实时特征更新:用户行为(点击/滑动/停留)通过埋点上报 → Kafka → Flink 实时计算 → 写入特征存储(Redis / Feature Store)→ 排序模型实时读取。


实战案例

案例一:电商商品搜索

背景:商品数量 5000 万,支持中文全文搜索、价格/类目过滤、按销量/评分排序。

架构设计

用户搜索请求

搜索服务(Query 解析、同义词扩展)

Elasticsearch 集群(3 个 Data Node,共 10 个 Primary Shard)

返回结果(高亮 + 聚合统计)

数据同步链路:
MySQL(商品库)→ Canal → Kafka → ES Consumer → Elasticsearch

关键设计决策

  1. 中文分词:title 字段同时索引 ik_max_word(检索)和 ik_smart(高亮),兼顾召回率和精准度
  2. 同义词:搜索"手机"时自动扩展"智能手机"、"移动电话"
  3. 价格/库存过滤:用 filter 子句(不影响评分,有缓存)
  4. 排序:支持按相关性(默认)、销量、价格、上架时间多维度排序
  5. 缓存:热门搜索词结果缓存到 Redis,TTL 5 分钟

案例二:短视频推荐 Feed

背景:日活用户 5000 万,视频库 10 亿,要求首屏 200ms 内返回推荐列表。

四阶段流程

1. 召回(< 50ms)
   - UserCF:基于相似用户历史喜好
   - ItemCF:基于用户最近看过的视频
   - 向量召回:用户兴趣向量 ANN 检索(Faiss)
   - 热门兜底:保证新用户也有内容
   → 合并得到 ~1000 个候选视频

2. 粗排(< 30ms)
   - 用轻量 GBDT 模型预估 CTR
   - 过滤用户已看过的视频、违规内容
   → 保留 ~200 个

3. 精排(< 80ms)
   - DeepFM 模型预估 CTR、完播率、点赞率
   - 综合评分 = α×CTR + β×完播率 + γ×点赞率
   → 保留 ~20 个

4. 重排(< 20ms)
   - 同作者/同话题打散(避免连续推同类)
   - 插入广告(按策略)
   - 新视频强插(保证新内容曝光)
   → 最终返回 10 个

实时特征:用户当前会话的最近 5 次点击行为通过 Flink 实时计算,注入精排特征。


面试常问 & 怎么答

Q1:ES 和 MySQL 全文索引的区别?

怎么答

从三个维度展开——底层结构、功能能力、适用场景。

  • 底层结构:MySQL 全文索引基于 B+ 树或倒排索引(InnoDB FTS),但实现较为简单;ES 的倒排索引更完善,天然支持分布式、分片。
  • 功能能力:ES 支持中文分词(IK)、多字段搜索、相关性评分(BM25)、高亮、聚合分析、近实时搜索;MySQL 全文索引不支持中文(需插件)、功能有限。
  • 扩展性:ES 横向扩展简单(加节点),MySQL 全文检索在大数据量下性能急剧下降。
  • 结论:简单场景(数据量小、只需 LIKE)用 MySQL;复杂全文检索(中文、相关性、大数据量)上 ES,数据通过 Canal + Kafka 同步。

Q2:推荐系统如何解决冷启动问题?

怎么答

新用户冷启动新物品冷启动分别回答。

新用户冷启动

  1. 注册时收集基础信息(年龄、城市、兴趣偏好选择)
  2. 前期推送热门内容、平台爆款
  3. 根据用户前几次行为快速更新兴趣模型(探索期,多样性优先)
  4. 利用物品内容特征(Content-Based)做冷启动推荐

新物品冷启动

  1. 初期强制给一定曝光量(流量倾斜)
  2. 用物品的标签/类目做基于内容的匹配,推给相关兴趣用户
  3. 通过 Bandit 算法(UCB、Thompson Sampling)平衡探索与利用
  4. 收集足够点击数据后过渡到协同过滤

Q3:倒排索引的原理?为什么搜索速度快?

怎么答

原理:文档写入时,分析器将文本拆分为词项(Token),建立"词项 → 文档列表"的映射表,即倒排索引。每个词项对应一个 Posting List,记录包含该词项的所有文档 ID 及词频、位置信息。

为什么快

  1. 查询时直接查词项表,O(1) 定位(哈希或 B 树),无需全表扫描
  2. 多词查询只需对 Posting List 做集合运算(AND/OR),高度优化
  3. Posting List 经过压缩(Frame of Reference、Roaring Bitmap),内存占用小,可缓存

对比全表扫描(LIKE '%关键词%'):全表扫描是 O(N×M),倒排索引是 O(词表查找 + Posting List 合并),数量级差异在大数据量下极为显著。


看到什么就先想到这类

看到这些关键词先想到
全文搜索 / 关键词匹配Elasticsearch + 倒排索引
搜索相关性 / 排序不准BM25 / TF-IDF / 字段权重调优
中文搜索 / 拼音搜索IK 分词器 / Pinyin 分析器
个性化推荐 / Feed 流召回 → 粗排 → 精排 → 重排 Pipeline
冷启动(新用户/新内容)热门兜底 + 内容推荐 + Bandit 算法
实时特征 / 行为实时更新Flink + Kafka 实时计算
数据库数据同步到 ESCanal + Kafka + Consumer
海量候选快速过滤多路召回 + 粗排
推荐多样性 / 避免信息茧房重排阶段 MMR / 打散策略