跳转到内容

Search Engine — 搜索引擎

公司内部有一个 Wiki 知识库,大概 200 篇文档,全部是纯文本。同事们抱怨每次找文档只能靠目录一个个翻,效率太低了。老板让你做个搜索功能,能输入关键词快速找到文档。文档量不大,不需要后端,越快上线越好。

在浏览器中实现模糊搜索,从静态 JSON 数据中快速查找匹配文档并高亮显示关键词。

用纯前端实现一个文档搜索页面,要求:
1. 所有文档硬编码为 JSON 数组,每个文档有 id、title、content、category 字段
2. 准备 15 篇示例文档,涵盖技术、产品、设计三个分类
3. 使用 Fuse.js 实现模糊搜索(CDN 引入)
4. 搜索输入框支持实时搜索(debounce 300ms)
5. 搜索结果列表显示:标题、内容摘要(前 150 字)、分类标签
6. 关键词在标题和摘要中高亮显示(黄色背景)
7. 支持按分类筛选
8. 无结果时显示友好提示
9. 单个 HTML 文件,内联 CSS,不需要任何后端
输出一个可以直接打开的 HTML 文件。
  • 打开 HTML 文件,搜索框可用
  • 输入关键词后 300ms 内显示结果
  • 模糊搜索有效(输入错别字仍能匹配)
  • 关键词高亮显示正确
  • 分类筛选功能正常
  • 无结果时显示提示文字
  • 前端模糊搜索库(Fuse.js)的使用 → M10
  • Debounce 防抖优化用户体验 → M1
  • 客户端搜索的适用场景和局限性 → M10

V2「文档有 3000 篇了,浏览器搜索卡了 3 秒」

Section titled “V2「文档有 3000 篇了,浏览器搜索卡了 3 秒」”

Wiki 用了半年,文档从 200 篇涨到了 3000 篇。每次搜索要把 3000 篇文档的 JSON 全部加载到浏览器里,首次加载要 5 秒,搜索一次卡 3 秒。用户开始投诉,说搜索比翻目录还慢。前端模糊搜索已经撑不住这个数据量了。

将搜索逻辑迁移到后端,用内存倒排索引实现毫秒级全文检索。

用 Go + Gin 实现一个文档搜索后端服务,要求:
1. 启动时从 ./docs/ 目录读取所有 JSON 文件,每个文件包含 id、title、content、category
2. 在内存中构建倒排索引:map[string][]DocID
3. 分词规则:按空格、标点符号分割,转小写
4. 提供搜索 API:GET /api/search?q=关键词&category=分类&page=1&size=20
5. 搜索逻辑:查询倒排索引,取交集,按匹配度排序(匹配字段越多分数越高)
6. 返回结果包含:文档列表、总数、耗时(毫秒)
7. 提供一个简单的前端搜索页面(HTML)
8. 准备 20 个示例 JSON 文档文件用于测试
9. 启动时打印索引构建耗时和文档总数
输出完整的项目结构和代码。
  • 服务启动时成功加载文档并构建索引
  • 搜索 API 返回正确结果,响应时间 < 50ms
  • 分页参数生效
  • 分类筛选正常
  • 多关键词搜索取交集
  • 返回搜索耗时信息
  • 倒排索引的原理和实现 → M10
  • 内存数据结构选型(map vs trie) → M2
  • 分词策略对搜索质量的影响 → M9
  • 前端搜索 vs 后端搜索的临界点 → M8

V3「搜”机器学习”搜不到标题是”ML”的文档,也搜不到内容里的”deep learning”」

Section titled “V3「搜”机器学习”搜不到标题是”ML”的文档,也搜不到内容里的”deep learning”」”

后端搜索上线后,速度问题解决了。但新问题来了:用户搜”机器学习”,搜不到标题是”ML”的文档;搜”数据库”,搜不到内容里写的”database”的文章;中文文档搜索效果很差,“机器学习”被当成一个整体,搜”机器”找不到”机器学习”的文档。团队需要一个真正懂语义的搜索引擎。

引入 Elasticsearch 实现支持中文分词、同义词扩展和相关性排序的专业搜索。

用 Go + Gin + Elasticsearch 实现一个专业文档搜索系统,要求:
1. Docker Compose 启动 Elasticsearch 8.x(单节点,关闭安全认证方便开发)
2. 创建索引时配置:
- 中文分词器:ik_max_word(索引时)和 ik_smart(搜索时)
- 同义词过滤器:ML=机器学习=machine learning, DB=数据库=database 等
- 自定义分析器组合中文分词 + 同义词
3. 文档结构:id, title, content, category, tags, created_at
4. 搜索 API:GET /api/search?q=关键词&category=&page=1&size=20
5. 搜索逻辑:
- multi_match 查询,搜索 title(权重 3)和 content(权重 1)
- BM25 相关性评分
- 高亮返回(<em> 标签包裹匹配词)
6. 提供文档 CRUD API 和批量导入接口
7. 搜索建议 API:GET /api/suggest?q=前缀(用 completion suggester)
8. 前端页面展示搜索结果,显示高亮和相关性分数
9. 准备 30 篇中英文混合示例文档和同义词词典文件
输出完整项目结构、docker-compose.yml、索引映射配置和代码。
  • Elasticsearch 容器正常启动
  • 中文分词生效(“机器学习”能被拆分为”机器”和”学习”)
  • 同义词搜索有效(搜”ML”能找到”机器学习”的文档)
  • 搜索结果按相关性排序(标题匹配排在前面)
  • 高亮标签正确返回
  • 搜索建议功能正常
  • 批量导入接口可用
  • Elasticsearch 索引映射和分析器配置 → M10
  • 中文分词器(IK)的工作原理 → M9
  • 同义词扩展和多语言搜索策略 → M10
  • BM25 评分算法和相关性调优 → M10
  • Completion Suggester 实现搜索建议 → M10
  • 从自建索引到搜索引擎的演进决策 → M8

V4「搜索结果要支持筛选和排序,搜索建议也要加上」

Section titled “V4「搜索结果要支持筛选和排序,搜索建议也要加上」”

文档量涨到 1000 用户在用,大家反馈搜索结果太多,找不到想要的。用户希望能按作者、日期、分类多维度筛选搜索结果,还希望输入几个字就能弹出搜索建议。另外,运营想知道用户都在搜什么,以便优化文档内容。

实现 Faceted Search(分面搜索)支持按作者、日期、分类筛选;用前缀匹配实现自动补全;搭建搜索分析日志记录热门查询。

在现有 Go + Gin + Elasticsearch 搜索系统基础上,增加以下功能:
1. Faceted Search(分面搜索):
- 搜索结果返回 aggregation 统计:按 category 分组计数、按 author 分组计数、按 created_at 按月分组计数
- 前端左侧显示筛选面板,点击分面项可叠加筛选条件
- 支持多选筛选(如同时选两个分类)
- 筛选后 aggregation 数值实时更新
2. 自动补全(Autocomplete):
- GET /api/autocomplete?q=前缀&limit=10
- 使用 Elasticsearch edge_ngram tokenizer 实现前缀匹配
- 返回匹配的文档标题和分类
- 前端搜索框下拉展示建议列表,键盘上下键可选择
- debounce 200ms,最少输入 2 个字符触发
3. 搜索分析(Search Analytics):
- 每次搜索记录到 search_logs 表:query, result_count, user_id, timestamp
- GET /api/admin/analytics/top-queries?days=7&limit=20 — 热门搜索词 TOP 20
- GET /api/admin/analytics/zero-results?days=7 — 零结果搜索词列表
- 管理后台页面展示搜索趋势图表
4. 搜索结果排序增强:
- 支持按相关性、日期最新、日期最旧三种排序
- 前端排序下拉框切换
输出增量代码和修改说明。
  • 搜索结果包含 facet 聚合数据(分类、作者、日期分布)
  • 点击分面筛选后结果和聚合数据正确更新
  • 多选筛选叠加生效
  • 自动补全输入 2 个字符后弹出建议
  • 建议列表支持键盘导航和回车选择
  • 搜索日志正确记录到数据库
  • 热门搜索词和零结果搜索词接口返回正确
  • 排序切换功能正常
  • Elasticsearch Aggregation 实现分面搜索 → M10
  • Edge N-gram Tokenizer 实现前缀匹配自动补全 → M10
  • 搜索日志分析和零结果优化策略 → M15
  • 用户搜索行为数据驱动内容优化 → M9
  • 多维筛选的查询构建模式(Bool Query) → M10

V5「文档量到百万级,单节点 ES 查询超时」

Section titled “V5「文档量到百万级,单节点 ES 查询超时」”

搜索系统接入了公司所有业务线,用户量达到 1 万,文档量突破 100 万篇。单节点 Elasticsearch 的查询延迟从 50ms 飙升到 2 秒,高峰期直接超时。索引大小超过 50GB,单机磁盘快满了。重建索引要跑 6 小时,期间搜索不可用。

搭建 Elasticsearch 多节点集群,设计索引分片策略,引入搜索结果缓存,优化查询性能(先过滤再评分)。

将现有单节点 Elasticsearch 搜索系统升级为高可用集群架构,要求:
1. Elasticsearch 集群部署:
- Docker Compose 配置 3 节点 ES 集群(1 master + 2 data nodes)
- 集群健康检查和节点发现配置
- 每个节点分配独立的 data volume
2. 索引分片策略:
- 主索引按月分片:docs_2024_01, docs_2024_02, ...
- 使用 index alias 统一查询入口:docs_current 指向最近 6 个月索引
- Index Template 统一管理索引设置和映射
- 旧索引自动设为 read-only 并 force merge 为 1 segment
3. 搜索结果缓存:
- Redis 缓存热门查询结果,key 为 query+filters 的 hash
- 缓存 TTL 3 分钟,文档更新时清除相关缓存
- 缓存命中率监控接口
4. 查询性能优化:
- 使用 filter context 替代 query context 处理精确匹配(分类、日期范围)
- filter 走 bitset 缓存,不计算评分
- 大结果集使用 search_after 替代 from+size 深分页
- 限制返回字段(_source filtering),只返回需要的字段
5. 零停机重建索引:
- Reindex API 从旧索引迁移到新索引
- Alias 切换实现零停机切换
- 重建期间增量数据同步方案
6. 监控和告警:
- 集群健康状态监控(green/yellow/red)
- 慢查询日志(>500ms)
- 节点磁盘和 JVM 堆内存监控
输出 Docker Compose 配置、索引模板、查询优化代码和运维脚本。
  • 3 节点集群正常启动,集群状态 green
  • 按月分片索引创建成功,alias 查询跨索引生效
  • Index Template 自动应用到新索引
  • 100 万文档下搜索延迟 < 200ms
  • Redis 缓存命中时延迟 < 10ms
  • filter context 查询不计算评分(EXPLAIN 验证)
  • search_after 深分页正常工作
  • 零停机 reindex 切换成功
  • 慢查询日志正确记录
  • Elasticsearch 集群架构(master/data 节点角色) → M8
  • 索引分片策略和 Alias 管理 → M10
  • Filter Context vs Query Context 的性能差异 → M10
  • 搜索结果缓存设计和失效策略 → M4
  • 深分页问题和 search_after 方案 → M2
  • 零停机索引重建(Reindex + Alias 切换) → M16
  • ES 集群监控和慢查询分析 → M15

V6「要支持多语言,还要用 AI 做语义搜索」

Section titled “V6「要支持多语言,还要用 AI 做语义搜索」”

公司全球化扩张,用户超过 10 万,文档覆盖中、英、日、韩多种语言。用户搜”如何部署服务”,希望也能找到英文的”how to deploy service”文档。更大的痛点是:用户搜”怎么让程序跑得更快”,现有关键词搜索完全匹配不到标题是”性能优化指南”的文档。业务要求搜索能”理解”用户意图,而不仅仅是匹配关键词。

引入向量搜索(AI 生成 Embedding)实现语义搜索,结合关键词搜索实现混合检索;配置多语言分析器;用 LLM 做查询理解和改写。

在现有 Elasticsearch 集群基础上,构建支持多语言和 AI 语义搜索的系统,要求:
1. 向量搜索(Vector Search):
- 文档入库时调用 Embedding API(OpenAI text-embedding-3-small 或开源替代)生成 768 维向量
- Elasticsearch 8.x dense_vector 字段存储向量
- 使用 kNN search 实现语义搜索
- 异步向量生成:文档写入后通过消息队列异步生成 embedding,避免阻塞写入
2. 混合搜索(Hybrid Search):
- 同时执行关键词搜索(BM25)和向量搜索(kNN)
- RRF(Reciprocal Rank Fusion)算法合并两路结果
- 可配置关键词权重和语义权重的比例
- 前端可切换搜索模式:关键词 / 语义 / 混合
3. 多语言支持:
- 为不同语言配置专用分析器:中文(ik)、英文(standard)、日文(kuromoji)、韩文(nori)
- 文档入库时自动检测语言(用 langdetect 库)
- 搜索时自动检测查询语言,路由到对应语言的索引
- 跨语言搜索通过向量搜索实现(embedding 天然跨语言)
4. 查询理解(Query Understanding):
- 搜索前调用 LLM 分析用户意图
- 查询改写:口语化查询 → 标准化查询("怎么让程序跑得更快" → "性能优化")
- 查询扩展:自动补充相关术语
- 意图分类:信息查询 / 导航查询 / 操作查询
- LLM 调用做降级处理:超时或失败时 fallback 到原始查询
5. 基础设施:
- 向量生成 Worker 集群(消费消息队列,调用 Embedding API)
- Embedding 结果缓存(相同文本不重复调用 API)
- 多区域 Elasticsearch 集群,搜索请求就近路由
- CDN 缓存静态搜索页面资源
输出系统架构图描述、核心代码、部署配置和性能测试方案。
  • 文档入库后异步生成 embedding 并写入 ES
  • 语义搜索能找到关键词不匹配但语义相关的文档
  • 混合搜索结果优于纯关键词或纯语义搜索
  • RRF 合并排序结果合理
  • 多语言文档自动检测语言并分配到正确索引
  • 跨语言搜索生效(中文查询找到英文文档)
  • 查询改写提升搜索准确率
  • LLM 超时时降级到原始查询正常返回
  • 向量生成 Worker 消费队列正常
  • Embedding 缓存命中时不重复调用 API
  • 向量搜索和 Embedding 的原理与实践 → M10
  • 混合检索(BM25 + kNN)和 RRF 融合算法 → M10
  • 多语言分析器配置和语言检测 → M9
  • LLM 集成:查询理解、改写和降级策略 → M9
  • 异步向量生成和消息队列解耦 → M5
  • Embedding 缓存避免重复计算 → M4
  • 多区域部署和就近路由 → M17
  • CDN 加速静态资源 → M13
  • 从关键词搜索到语义搜索的架构演进 → M8