
搜索联想功能的核心不是“前端输几个字就发请求”,而是后端要能快速返回匹配的关键词候选项——Laravel 本身不内置联想逻辑,得靠数据库查询优化 + 接口设计来实现。
用 LIKE 还是全文索引?
简单场景下直接用 LIKE '%keyword%' 最快上手,但数据量一过万行就会明显变慢;MySQL 的 FULLTEXT 索引或 PostgreSQL 的 tsvector 更适合高并发、长文本匹配。但注意:中文分词需额外配置(如 MySQL 的 ngram 插件),否则 FULLTEXT 对中文基本无效。
- 小项目(where('title', 'like', "%{$keyword}%")
- 中大型项目:优先考虑
WHERE title LIKE '{$keyword}%'(前缀匹配),配合 B-Tree 索引可走索引 - 需要模糊/错别字容错:引入
pg_trgm(PostgreSQL)或第三方服务(如 Algolia、Elasticsearch)
SearchController@suggest 接口怎么写才不卡
联想接口必须限制返回数量、禁止全表扫描、避免 N+1。典型错误是查出全部匹配记录再用 PHP 截取,这会拖垮数据库连接池。
- 一定要加
->limit(10),前端最多展示 10 条,后端别多给 - 避免
select('*'),只查必要字段,比如select('id', 'title') - 如果关联了分类、作者等,别在联想接口里
with(),留到点击后详情页再查 - 加缓存?谨慎:用户输入是任意字符串,缓存 key 难控制,不如把高频词(如热搜前 20)单独缓存
为什么输入 “php” 返回了 “phpstorm” 却没返回 “PHP 教程”?
这是大小写和字段内容结构导致的。默认 MySQL 的 utf8mb4_general_ci 排序规则不区分大小写,但如果你用的是 utf8mb4_bin,或者字段值开头是空格、换行、emoji,就可能漏匹配。
- 检查字段 collation:运行
SHOW FULL COLUMNS FROM posts LIKE 'title';,确认是utf8mb4_unicode_ci类型 - 避免用
LOWER()包裹字段做查询(如whereRaw('LOWER(title) LIKE ?')),这会让索引失效 - 如果标题含 HTML 标签或富文本,先清洗再入库,或建一个
title_search纯文本冗余字段专门用于联想
真正难的不是写出第一个可用版本,而是当用户搜“js”时,既要返回“JavaScript”,也要压住“json-server”这类低相关结果——这得靠权重排序,而 Laravel 默认 ORM 不提供字段权重语法,得手写 DB::raw() 或切到 Scout + Algolia 才容易落地。










