laravel scout + meilisearch 是最轻量、响应最快且不依赖 mysql 全文索引的搜索方案,需确保 meilisearch 正常运行、正确配置 key 和 host,模型中 tosearchablearray() 返回有效数组,中文需设置 searchableattributes,导入后验证索引内容,搜索时注意排序、过滤及容错配置。

直接用 Laravel Scout + Meilisearch 是目前最轻量、响应最快、且不依赖 MySQL 全文索引配置的方案。它把搜索逻辑完全交给 Meilisearch,避免了 WHERE MATCH AGAINST 的语法限制和分词能力弱的问题。
确认 Meilisearch 服务已就绪并可连通
Scout 不会帮你启动或管理 Meilisearch 实例,必须先确保它在运行且 Laravel 能访问到。常见踩坑点是本地开发时用了默认端口但没开防火墙,或 Docker 容器网络不通。
- 启动 Meilisearch(推荐 Docker):
docker run -d -p 7700:7700 -v $(pwd)/data:/data.ms getmeili/meilisearch:v1.10 - 检查连通性:
curl http://127.0.0.1:7700/health应返回{"status":"available"} - 注意:Meilisearch v1.0+ 默认 key 是
masterKey,不是空字符串;.env中需设MEILISEARCH_KEY=masterKey - 若用 WSL 或远程服务器,
host配置不能写127.0.0.1,得换为宿主机 IP 或host.docker.internal
模型中 toSearchableArray() 返回内容决定能搜什么
Scout 不自动索引全部字段,也不强制要求字段可搜索;toSearchableArray() 返回空、漏字段、或含 N+1 查询,都会导致搜索结果为空或不准。
- 必须返回非空数组,禁止写成
return []或return null - 中文搜索需确保字段在 Meilisearch 后台被标记为 searchable,例如手动执行:
curl -X PATCH 'http://localhost:7700/indexes/articles/settings' -H 'Content-Type: application/json' -d '{"searchableAttributes": ["title", "content"]}' - 避免在
toSearchableArray()中调用$this->load()或访问未预加载的关联属性,否则索引过程会变慢甚至失败 - 时间字段建议转为 timestamp 或格式化字符串,避免 Carbon 对象序列化失败
导入数据后仍搜不到?先查索引里有没有
Scout 的 scout:import 命令只负责把数据推过去,不校验是否成功写入。很多“搜不到”问题其实出在索引本身没建好,或字段未生效。
- 手动查索引内容(以
articles索引为例):curl 'http://localhost:7700/indexes/articles/search' -d '{"q":"laravel"}' - 如果返回空或
"nbHits": 0,说明数据根本没进索引——优先检查toSearchableArray()输出、日志是否有异常、以及 Meilisearch 是否启用了正确的locales(v1.8+ 中文默认支持,旧版需显式设"locales": ["zh"]) - 执行
php artisan scout:import "App\Models\Article"后,务必等命令输出Imported 123 records再测试,不要看到命令结束就以为完成 - 若用队列驱动同步,确认
APP_ENV=local且QUEUE_CONNECTION=sync(开发环境)或队列进程确实在跑(生产环境)
搜索时结果排序混乱或相关性低
Meilisearch 默认按 _score 排序,但业务常需要按时间、热度等二次排序,且默认匹配可能把标题含关键词但正文无关的记录排太前。
- 基础搜索:
Article::search('laravel')->get()返回 Eloquent 集合,但无法链式调用orderBy()—— 必须用->orderBy('published_at', 'desc')才有效 - 过滤条件要放在
search()之后、get()之前:Article::search('api')->where('status', 'published')->get() - 如需更高容错(比如拼写错误、部分匹配),启用 Meilisearch 的 typo tolerance 和 prefix search:
Article::search('laravle')->with(['typoTolerance' => true, 'prefix' => true])->get() - 慎用
->paginate():它底层会发两次请求(一次取总数、一次取数据),高并发下可能造成不一致;小数据量建议用->simplePaginate()
最常被忽略的是:Meilisearch 的索引名称默认取模型类名复数(如 articles),但如果你改过 $table 或用了自定义索引名,scout:import 和实际搜索用的索引可能不一致——得核对 config/scout.php 里的 prefix 和模型的 searchableAs() 方法。











