茶叶商城的商品到了 2 万多条,搜索先撑不住了。原来一句 LIKE %关键词%,品名里写「铁观音 清香型 250g」,用户搜「铁观音」还凑合,搜「清香铁观音」就一条不出。
为什么不是加索引
LIKE 前面带百分号,普通 B-tree 索引用不上。想过用全文索引,但商品名里中文、数字、单位混着,还有一堆别名,改起来不比换方案省。数据量 2 万多条,Elasticsearch 有点杀鸡用牛刀,可客户后面还要按品类、产地、价格区间筛,就一起做了。
第一版分词翻车
mapping 没细配,直接灌数据。搜「安溪铁观音」,默认分词把每个字拆开,结果里冒出一堆只含「安」或者「溪」的别的商品,排序也乱。搜「铁观音」倒是能出,但排在前面的不是最相关的那几个。
重做了一遍 mapping:
- 品名字段索引用 ik_max_word,尽量拆细,保证能被各种说法命中。
- 搜索时用 ik_smart,拆得粗一点,避免把查询词也拆成一堆单字去匹配。
- 另建一个 pinyin 字段,搜「tieguanyin」也能出,客服说有人习惯打拼音。
- 别名放一个单独字段,权重调高一点,比如「铁观音」和「观音王」指向同一批货。
调完拿 30 个真实搜索词跑了一遍,把结果前 5 条打出来给客户运营看,标了 6 个不满意的,又调了一轮权重。
同步怎么保持
没做双写。MySQL 是主,商品表加了一个 updated_at,定时任务每 10 分钟扫一次增量,变了就重新索引那批 id。删除走软删,索引里同步标一下状态。
最坏情况有 10 分钟延迟,客户能接受,价改错了宁可晚一会儿显示,也别即时冲进去。真要立刻生效,后台留了个「立即同步」按钮,运营改完自己点。
那 6 个不满意的词是什么
运营标出来的 6 个,我们逐个看过。两个是别名没覆盖:「观音王」搜不出铁观音、「大红袍」被拆成了「大」「红」「袍」。补进别名字段,权重给到比品名高一档。三个是数字和单位:「250g」「半斤」「一斤装」,原来都没进索引,后来把规格字段单独建了个子字段,搜「半斤」也能命中 250g 那批。
最后一个是「铁观音 清香型」,用户把品名和香型连着搜。原来香型只在筛选项里,没进搜索字段。加进去了,但没给太高权重,免得只因香型匹配就把别的茶排到前面。
调完又跑了一遍那 30 个词,前 5 条里不满意的剩 1 个,是个生僻的产地名,商品库里压根没那款茶。运营说这个不用管,本来就没有。
拼音字段那个小坑
pinyin 字段上线后,搜「tieguanyin」能出,搜「tie guan yin」带空格就不行。分词配置里没处理空格,后来把查询串先去空格再送进去,顺手把全拼和首字母两种都建了,搜「tgy」也能出。客服那边挺高兴,说有人就爱打三个字母。
索引重建那次
改 mapping 要重建索引,2 万多条全量灌一次大概 4 分钟。我们没停服,先建了个带版本号的新索引,灌完把别名指过去,旧的留了一天再删。这套做法是从灰度那边借的,换了个地方用。
10 分钟增量同步至今没出过大问题,只有一回运维误把定时任务停了三个小时,运营发现新上的商品搜不到,补跑一次就好,后来给这个任务也加了告警。零结果词那份表现在每月自动发到运营邮箱,不用我们导了,最近一次表里排第一的是「赠品袋」,库里确实没有这个商品。
一个没料到的用处
上线后搜得最多的不是茶名,是「赠品」「试饮」「礼盒」。这三个词原来在 LIKE 时代基本搜不出东西,因为都写在详情里不在品名。后来把详情里的前 200 字也索引了,才算能用。
运营那边每月导一次「零结果搜索词」,看用户找了什么但没找到。那份表比任何搜索优化建议都实在。

