Scout是Laravel官方推荐的跨模型搜索方案,支持多模型聚合检索;需安装scout及Meilisearch驱动,各模型添加Searchable trait并实现toSearchableArray(),导入数据后用Model::search()->get()即可。

用 Scout 实现跨模型搜索最省事
Laravel 官方推荐的全局搜索方案就是 Scout,它不绑定具体模型,天然支持多模型聚合检索。别自己写 LIKE 拼接或手动 UNION —— 性能差、分页错、权重没法调。
实操建议:
- 先装
scout和对应驱动(推荐meilisearch,本地启动快、中文分词友好;algolia要网络、要 API Key) - 每个要搜的模型加
Searchabletrait,并实现toSearchableArray()控制字段 - 执行
php artisan scout:import "App\Models\Post"导入数据,别漏掉User、Product等其他模型 - 搜索时用
Model::search('关键词')->get(),结果自动带模型类型和 ID,不用自己 union 合并
手动 UNION 搜索容易翻车的三个点
有人图省事直接在查询构造器里 union 多个 select,但实际会遇到硬伤:
- 字段数必须严格一致 ——
User有name、email,Post有title、content,得统一补NULL as email这类占位,一漏就报SQLSTATE[HY000]: General error: 1222 The used SELECT statements have a different number of columns - 分页失效 ——
union结果不能直接套paginate(),得用子查询包装,否则total()错、perPage不生效 - 排序靠后 —— 所有模型字段得映射到同一组别名(如都叫
relevance),不然orderBy('relevance')只对最后一个select生效
Scout + Meilisearch 中文搜索要关掉 typo tolerance
meilisearch 默认开启拼写容错,对英文友好,但搜「微信」可能返回「威信」「微 Xin」,中文场景下干扰大。
解决方法是在索引配置里关掉:
curl -X POST 'http://localhost:7700/indexes/posts/settings' \
-H 'Content-Type: application/json' \
--data-binary '{"typoTolerance": {"enabled": false}}'
或者用 Laravel Scout 的 MeiliSearchEngine 自定义设置,在 config/scout.php 加:
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
'meilisearch' => [
'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
'key' => env('MEILISEARCH_KEY', ''),
'index-settings' => [
'typoTolerance' => ['enabled' => false],
],
],
搜索结果里区分模型类型必须显式取 $model->getMorphClass()
Scout 返回的是原模型实例,但前端需要知道这条是 App\Models\User 还是 App\Models\Comment,不能只靠 get_class($item) —— 因为可能被代理或封装过。
正确做法是:
- 统一用
$item->getMorphClass()获取注册时的短名(如users、posts) - 如果没重写
getMorphClass(),默认返回完整命名空间,前端难处理,建议在模型里加:
public function getMorphClass()
{
return 'user';
}
否则前端拿到 App\Models\User 得自己截字符串,容易出错。
跨模型搜索真正的麻烦不在怎么查,而在怎么让不同结构的数据在同一个结果集里语义清晰、分页准确、前端可渲染 —— 这些细节不提前对齐,上线后改起来比重写还累。










