laravel scout + meilisearch 是最轻量、响应最快且不依赖 mysql 全文索引的方案,需确保 meilisearch 服务就绪、.env 与 config/scout.php 配置一致、tosearchablearray() 正确返回索引字段,并验证数据已真实写入索引。

直接用 Laravel Scout + Meilisearch 是目前最轻量、响应最快、且不依赖 MySQL 全文索引的方案。它把搜索逻辑完全交给 Meilisearch,避免了 WHERE MATCH AGAINST 的语法限制和分词能力弱的问题。但对接失败几乎都卡在“连不上”或“搜不到”,不是 Scout 写得不对,而是环境、配置、数据三者没对齐。
确认 Meilisearch 服务已就绪并可连通
Scout 不会帮你启动或管理 Meilisearch 实例,必须先确保它在运行且 Laravel 能访问到。常见踩坑点是本地开发时用了默认端口但没开防火墙,或 Docker 容器网络不通。
- 用 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"} - 若用 Laravel Sail,确认
sail up后meilisearch服务已启动,且MEILISEARCH_HOST=http://meilisearch:7700(不是localhost) - 生产环境别硬写
127.0.0.1,用域名或负载均衡地址,并确认防火墙放行 7700 端口
配置 .env 和 config/scout.php 中的 Meilisearch 段
驱动开关和连接参数必须同时生效,缺一不可。Laravel 会优先读取 .env,但 config/scout.php 里也要有对应结构,否则 Scout 初始化时会报错。
-
.env中必须设:SCOUT_DRIVER=meilisearch、MEILISEARCH_HOST=http://127.0.0.1:7700、MEILISEARCH_KEY=masterKey(v1.0+ 默认 key 是masterKey,不是空字符串) -
config/scout.php中的meilisearch键不能缺失,即使值来自 env:'meilisearch' => ['host' => env('MEILISEARCH_HOST', 'http://127.0.0.1:7700'), 'key' => env('MEILISEARCH_KEY', 'masterKey')] - 改完
.env后务必执行:php artisan config:clear,否则缓存旧配置,连错地址也不报错 - 不要在
config/scout.php里写死密钥,尤其不要提交到 Git;MEILISEARCH_KEY在生产环境应设为强随机值
模型中 toSearchableArray() 返回内容决定实际索引字段
Scout 不自动索引全部字段,toSearchableArray() 是唯一控制入口。返回空、字段名拼错、或含非法类型(如对象、资源),都会导致索引为空或搜索失败。
- 必须返回非空数组,禁止写成
return []或return null;示例正确写法:return $this->only(['id', 'title', 'content']) - 中文字段没问题,但避免在该方法里调用
$this->load()—— 会触发 N+1 查询,且 Scout 同步是异步的,容易超时 - 关联数据需提前处理:比如标签要转成数组,
'tags' => $this->tags->pluck('name')->toArray(),而不是传整个集合 - 时间字段建议转为 timestamp 或格式化字符串,
published_at直接传Carbon对象可能被序列化失败
首次导入数据后必须验证索引是否真实写入
执行 php artisan scout:import "App\Models\Article" 只是触发导入命令,不代表数据进了 Meilisearch。很多“搜不到”问题其实压根没进索引。
- 导入后立即查 Meilisearch API:
curl "http://127.0.0.1:7700/indexes/articles/search?q=test"(articles是默认索引名,即模型名小写复数) - 若返回
"hits": [],说明索引为空;检查toSearchableArray()是否真返回了数据,或模型是否被shouldBeSearchable()过滤掉了 - 若用队列同步(
scout:sync或 save() 触发),确保队列监听器在运行:php artisan queue:work - Meilisearch 默认开启 typo tolerance 和 prefix search,但不会自动分词中文 —— 需确认 Meilisearch v1.10+ 已启用
searchableAttributes和filterableAttributes,否则中文字段无法被匹配
最难排查的其实是“连上了但搜不到”,往往卡在 toSearchableArray() 返回空、索引名和模型名不一致、或 Meilisearch 的 searchableAttributes 没显式设置中文字段。这些地方没日志、不报错,只能手动 curl 验证索引内容。











