2026年04月18日/ 浏览 6
正文:
在实际项目开发中,跨模型搜索一直是业务系统的高频需求。无论是电商平台的商品与店铺联合搜索,还是内容管理系统的文章与标签联动查询,都需要优雅的解决方案。Laravel Eloquent 作为强大的ORM工具,配合其生态系统,为我们提供了多层次的实现路径。
先来看一个典型的多模型联合搜索场景:我们需要在新闻(News)和产品(Product)中同时搜索包含关键词”Laravel”的记录,并按时间倒序排列。原生Eloquent方案可通过UNION查询实现:
$news = News::select('id', 'title', 'content', 'created_at')
->where('title', 'like', '%Laravel%')
->orWhere('content', 'like', '%Laravel%');
$results = Product::select('id', 'name as title', 'description as content', 'created_at')
->where('name', 'like', '%Laravel%')
->orWhere('description', 'like', '%Laravel%')
->union($news)
->orderBy('created_at', 'desc')
->paginate(15);
这种方案虽然直接,但在大数据量下会出现性能瓶颈。更专业的做法是使用Laravel Scout配合搜索引擎实现全文检索。首先通过模型观察器同步数据到搜索索引:
class News extends Model
{
use Searchable;
public function toSearchableArray()
{
return [
'title' => $this->title,
'content' => $this->content,
'type' => 'news'
];
}
}
然后通过自定义搜索逻辑实现跨模型检索:
$results = Search::search('Laravel')
->within([News::class, Product::class])
->orderBy('created_at', 'desc')
->paginate(15);
对于需要实时权重计算的复杂场景,可以通过raw表达式实现相关性排序。比如给标题匹配更高权重:
$news = News::selectRaw("
id, title, content,
MATCH(title) AGAINST(? IN BOOLEAN MODE) * 2 +
MATCH(content) AGAINST(? IN BOOLEAN MODE) as relevance
", [$query, $query])
->whereRaw("MATCH(title, content) AGAINST(? IN BOOLEAN MODE)", [$query])
->orderByDesc('relevance');
关联模型搜索同样常见,比如搜索用户及其文章。通过闭包实现嵌套查询:
$users = User::with(['posts' => function($query) use ($keyword) {
$query->where('title', 'like', "%$keyword%");
}])->whereHas('posts', function($query) use ($keyword) {
$query->where('title', 'like', "%$keyword%");
})->get();
值得注意的是,所有搜索方案都需要考虑索引优化。对于MySQL,建议给搜索字段添加全文索引:
ALTER TABLE news ADD FULLTEXT index_title_content (title, content);
最后要提醒的是,业务场景决定技术选型。简单查询可用原生方案快速实现,复杂搜索推荐采用Scout配合Algolia或Meilisearch等专业引擎。始终记得通过chunk等方法处理大数据量操作,避免内存溢出。这些实践方案已在多个项目中验证,能有效平衡开发效率与系统性能。