零件齐了,开始总装
十五篇下来,老王的工具箱塞满了:IK 分词、mapping 设计、match 与 filter、BM25 与 function_score、高亮纠错、聚合报表、分片规划、数据同步。现在把它们组装成一条完整的搜索流水线。搜索系统 = 预处理、召回、过滤、排序、展示五段式,每一段都有明确的输入输出。
五段式流水线
用户输入「燕麦拿铁 大杯」
第一段 预处理:去空格、纠错、同义词扩展
第二段 召回:multi_match 多字段加权查倒排
第三段 过滤:filter 砍掉下架、无库存、渠道不符
第四段 排序:function_score 叠加销量与新品德分
第五段 展示:高亮词条、分页返回、聚合侧栏前几篇的组件各就各位:预处理接第 9 篇的纠错,召回接第 7 篇的 multi_match,过滤是 filter 上下文(顺便白嫖缓存),排序接第 8 篇的 function_score,展示接第 9 篇的高亮。流水线比单点技巧重要:顺序错了(先过滤后召回会漏文档,先排序后过滤会浪费算分),效果天差地别。
同义词:搜「咖啡」要能出「拿铁」
预处理段最有价值的一环是同义词。用户搜「咖啡」,商品里写的是「拿铁」「美式」,不配同义词就是零结果。ES 的 synonyms filter 有两个挂载位置,效果不同:
索引时同义词:建倒排时就扩展,查询效率高,但改词表要重建索引——词表一变,全量 reindex。搜索时同义词:只在查询侧扩展,词表热更新即生效,代价是每次查询都要多切多查。实践惯例:常用对(咖啡、coffee)放索引时,运营常改的热词(新品别名)放搜索时,两头平衡。
搜索日志:让数据替你调参
搜索上线不是终点。老王给搜索接口加了三层埋点:记录每次的 query、返回条数、用户点击了第几位。这三个字段能算出一组体检指标:零结果率(搜了啥啥没有——补词表、补纠错)、首位点击率(第一名没人点说明排序不对)、改写率(纠错触发频率)。搜索日志本身也存进 ES 一份,用第 11 篇的聚合出周报。让数据告诉你 function_score 的销量权重该加多少,比拍脑袋体面得多。
运营干预位:置顶、屏蔽、加权
总有些需求跟算法无关:活动单品必须置顶,违禁商品必须消失,品牌周要给某品牌加权。这些做成配置化的干预位,而不是每次改代码:置顶用 pinned 结果插在头部,屏蔽用 must_not 套一份商品黑名单 ID 表,加权用带时间的 function_score 规则(活动结束自动失效)。给运营一个后台,别让他们提工单改查询——这是搜索系统从「技术功能」变「产品」的分水岭。
监控三个数就够了
| 指标 | 健康线参考 | 异常时查什么 |
|---|---|---|
| P99 延迟 | 500ms 内 | 慢查询日志、深分页、聚合 size |
| 零结果率 | 10% 以下 | 词表覆盖、纠错开关、字段映射 |
| 同步延迟 | 秒级到分钟级 | 消息堆积、扫表水位、对账漂移 |
小结
产品化一句话:五段式定链路,同义词分两头,日志养排序,干预位给运营,三个数盯健康。搜索的上限不在 ES 版本,在反馈闭环转不转。
系统跑起来了,性能开始被放大镜看:某些查询 P99 飙到三秒。下一篇讲查询调优:profile 工具、慢查询日志与 query 改写手法。
评论 (0)