Поиск это одна из тех функций, которые сначала кажутся простыми, но быстро превращаются в сложную архитектурную задачу. На старте достаточно пары LIKE-запросов, однако по мере роста данных появляются проблемы с производительностью, релевантностью результатов и масштабируемостью.
Разберёмся, как правильно проектировать поиск в Laravel: от базового решения до production-уровня.
Почему обычный LIKE-поиск это не лучшее решение
Самая распространённая реализация выглядит примерно так:
Post::where('title', 'like', "%{$query}%")->get();Такой подход работает, но у него есть серьёзные ограничения:
плохо масштабируется на больших таблицах;
не учитывает релевантность результатов;
не умеет работать с опечатками;
не поддерживает сложные фильтры;
медленно работает при большом объёме данных.
Когда база данных начинает расти, подобные запросы становятся узким местом всей системы.
Базовый поиск через Eloquent
Для небольших проектов можно использовать стандартные возможности Eloquent.
Контроллер
public function search(Request $request)
{
$query = $request->input('q');
$posts = Post::query()
->where('title', 'like', "%{$query}%")
->orWhere('content', 'like', "%{$query}%")
->paginate(10);
return view('posts.index', compact('posts'));
}Форма поиска
<form method="GET" action="/search">
<input type="text" name="q" placeholder="Search..." value="{{ request('q') }}">
</form>Основные рекомендации
Используйте
paginate()вместоget().Ограничивайте количество полей.
Добавляйте индексы на поисковые колонки.
Это простой и понятный подход, но он подходит только для небольших наборов данных.
Улучшение архитектуры с помощью Query Scopes
Когда поиск становится сложнее, стоит вынести логику в Eloquent scopes. Это делает код чище и повторно используемым.
Пример scope
public function scopeSearch($query, $term)
{
return $query->where('title', 'like', "%{$term}%")
->orWhere('content', 'like', "%{$term}%");
}Использование
Post::search($request->q)->paginate(10);Преимущества:
чистый контроллер;
переиспользование логики;
удобная композиция фильтров.
Использование Full-Text Search в базе данных
Если проект работает на MySQL или PostgreSQL, можно использовать встроенный full-text search.
Пример MySQL
Post::whereFullText('content', $query)->get();Full-text поиск работает быстрее и лучше ранжирует результаты по релевантности.
В Laravel такие запросы можно комбинировать с обычными фильтрами и дополнительной обработкой результатов.
Production-подход: Laravel Scout
Когда данных становится много (десятки тысяч или миллионы записей), правильным решением становится использование специализированных поисковых движков.
Laravel предоставляет для этого пакет Laravel Scout который позволяет интегрировать:
Meilisearch
Algolia
Elasticsearch
Scout синхронизирует модели Laravel с поисковым индексом и выполняет быстрый поиск по нему.
Пример реализации Scout
Установка
composer require laravel/scoutПодключение к модели
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
}Поиск
$posts = Post::search($query)->get();Scout автоматически индексирует модели и делает поиск значительно быстрее.
Использование Meilisearch
Одним из популярных движков для Laravel является Meilisearch. Он обеспечивает:
полнотекстовый поиск;
tolerance к опечаткам;
поиск по синонимам;
фильтрацию и сортировку;
автодополнение.
Кроме того, он очень прост в установке и отлично подходит для SaaS-приложений.
Полезные практики
1. Индексируйте только нужные поля
public function toSearchableArray()
{
return [
'title' => $this->title,
'content' => $this->content,
];
}2. Используйте пагинацию
Никогда не возвращайте большие коллекции без paginate().
3. Ограничивайте результаты
Post::search($query)->take(20)->get();4. Добавляйте фильтры
Post::search($query)
->where('status', 'published')
->get();Как итог
Правильная реализация поиска в Laravel зависит от масштаба проекта.
Для небольших приложений достаточно:
LIKEзапросовEloquent scopes
Для средних проектов:
Full-text search в базе данных
Для крупных систем:
Laravel Scout
Meilisearch или Elasticsearch
Такой подход позволяет постепенно масштабировать поиск без переписывания всей системы.