加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.beijidao.cn/)- 应用程序、AI行业应用、CDN、低代码、区块链!
当前位置: 首页 > 运营中心 > 搜索优化 > 正文

索引漏洞正 silently 拖垮你的搜索体验

发布时间:2026-10-27 11:11:56 所属栏目:搜索优化 来源:DaWei
导读:  去年五月份,改版上线翻车——就是那个搜商品页,前端说“语义搜索增强”,后端说“倒排索引全量刷新”,PM拍板“体验跃迁”。我当天在工位上,左屏开着 Kibana 看 query latency 百分位,右屏是 Chrome DevTools 的 Network

  去年五月份,改版上线翻车——就是那个搜商品页,前端说“语义搜索增强”,后端说“倒排索引全量刷新”,PM拍板“体验跃迁”。我当天在工位上,左屏开着 Kibana 看 query latency 百分位,右屏是 Chrome DevTools 的 Network tab,一直卡在 XHR 里的 /api/v2/search?k=… 那行,Status 列停在 pending。键盘空格键卡了一下,按下去没反应,抬手去抠,指尖沾了点灰。


  不是崩,不是报错,不是超时。是慢得让你想重装浏览器——但重装没用,因为问题不在浏览器里。是搜索框输“蓝牙耳机”,回车,转圈两秒半,出来结果里混着三百七十二个节点里早该下线的 SKU:2019 款有线耳塞、停产的充电仓模具号、甚至一个还在 draft 状态的运营埋点文案。我敢打包票,那个“蓝牙耳机” query 的 term vector 里根本没刷进新 synonym expansion map,但 ES 没报错,它就 quietly 把旧 index alias 指向了没 reload 的 shard。你猜怎么着?健康检查全绿。green,green,green。连 health API 都在对你微笑。


  旁边老张去倒水,经过我桌时说“你这接口咋还挂着 pending 啊”,我没抬头,只嗯了一声,然后手指悬在 F5 上:抬手、按键、松手——再抬手、按键、松手——第三次我数了,从触发到 DOM render 完成用了十八毫秒,但 loading 状态持续了四点三秒。这中间那点时间,被吃在哪?log 不出,trace 不落,span 里只有三个 span:/search(200)、/search/click(204)、/search/ab-test-variant(304)。中间那块黑区,像被剪掉的胶片。我原以为是 CDN 缓存了 old index meta,结果 curl -I 一看,ETag 居然是 fresh 的。所以……不是缓存,是 index mapping 里有个字段明明标了 dynamic: strict,却偷偷接住了带新字段的 document,还照常 build inverted index。它不拒绝,它吞,它消化不良,但它继续工作。


  汤洒了一滴,在右屏边框下沿,褐色的,慢慢洇开。外卖是楼下那家川菜,酸辣粉,浮油还没凝。我拿纸巾擦,顺便扫了眼同事钉钉头像——测试小李刚发来截图,标题《搜索无异常》,下面贴着一张表格:TTFB < 800ms,HTTP 200 率 99.98%,关键词覆盖率 92%。我盯着“覆盖率”仨字看了六秒。覆盖率是拿什么算的?是拿 query log 去 match mapping schema?还是拿 query log 去 match 实际返回的 document 字段?没人问。没人觉得这俩不该一样。就像没人觉得 index alias 切换完还要等 refresh_interval 过一遍才能对齐 real-time query——这个我说不准,ES 社区 wiki 写得含糊,7.x 和 8.x 对 translog commit 的感知节奏也不同,我试过三次,两次成功,一次失败,失败那次没留 snapshot,所以现在我也不能断言是版本行为差异还是集群负载抖动。


  PM 第二天早上九点十五分冲进来,拎着保温杯,“用户反馈搜不到新品,是不是前端 debounce 设太长?”我摘下耳机,说:“你搜‘无线降噪’,看第一页第三条,那个 SKU 编号末尾带 R7 的,查库存服务返回 null,但 ES 还把它排第一。”他顿了两秒,说:“啊?它应该被 filter 掉啊。”我说:“filter 是你后端写的,不是 ES 写的。你传过来的 bool query 里根本没有 must_not exists sku_stock_status。”他眨了眨眼,转身就走,临出门撞了下门框——他最近换了个新发型,刘海有点翘,挡住一半视线。


文章配图,仅供参考

  后来我们把 search-service 的日志 level 从 WARN 调成 DEBUG,才发现它每分钟都在 retry 一条 failed index update:原因是某个 mapping template 里把 price 字段定义成了 keyword,但 bulk insert 的 document 却传了 float,ES 默认 coerce 关闭,于是整 batch rollback,可 alias 指向没动,上游压根不知道——因为 bulk API 返回 200,只是 body 里藏了个 error 数组,而我们的 client sdk 把 errors 当 warning 扔了。这个我敢打包票,我把那段 response body copy 出来 hexdump 过。可你知道最荒唐的是什么?上线两周后 QA 测出个 case:搜“苹果手机”,首页第二条显示“iPhone 15 Pro Max (已售罄)”,点进去 404。查了三天,最后发现不是数据问题,是 CMS 后台导出时把一个 deprecated 的 product-type taxonomy 错标为 active,而 search-indexer 认真地给它建了 doc,没加任何 business flag——它优胜劣汰?不,它只淘汰语法错误,不淘汰业务逻辑错误。它淘汰不了那种悄悄活下来的 dead code。


  我今天早上又看到 CSS 命名规范文档更新了,新增一条:“组件类名必须以 c- 开头,禁止使用 BEM 的 __ 或 --”。我笑了。我们连 index consistency 都守不住,还在乎 c- 还是 u-?上次 PR review 我提 comment 说“这里 index rebuild 加个 pre-check 是否所有 mapping field 已 apply”,后端回:“跑一遍太慢,信任 CI”。信任 CI?CI 只校验 JSON Schema,不校验倒排链对不对得上正排字段值。我们工资条上写着“云平台稳定性奖金”,但过去三个月,这笔钱发了两次,都是因为某次大促前临时 hotfix 了 indexing pipeline 的 timestamp precision bug——它不影响 count,只影响排序权重微偏,偏得不足以进告警,偏得足够让 A/B test 结论翻车。


  反正我现在改了习惯:每次上线索引变更,不再只盯 health green,也不光看 query qps。我会先手动 curl 一个确定已删除的文档 ID,看它是否还出现在 search result 里;再 grep logstash index pattern,确认那个 index name 确实被 new alias 指向;最后……最后我泡杯茶,等三分钟,看有没有人微信问“为啥搜不到 XXX”。如果有,我就知道,漏洞还在呼吸。它不声不响,但它一直在那儿。下次要不要写个脚本自动比对 alias target 和实际 shard list?算了,先修完这单 production incident,再看。手边这包茶叶快见底了。

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!