- Введение
- Установка
- Конфигурирование
- Локальная разработка
- Индексирование
- Поиск
- Добавление собственных поисковых систем
- Макрокоманды построителя поискового запроса
Laravel Scout предлагает простое решение на основе драйверов для добавления полнотекстового поиска вашим моделям Eloquent. Используя наблюдателей моделей, Scout будет автоматически синхронизировать ваши поисковые индексы с вашими записями Eloquent.
В настоящее время Scout поставляется с драйверами Algolia и MeiliSearch. Кроме того, Scout включает в себя драйвер collection
, предназначенный для использования при локальной разработке и не требующий каких-либо внешних зависимостей или сторонних сервисов. Более того, написать свой собственный драйвер просто, и вы можете расширить Scout собственной реализацией поиска.
Для начала установите Scout с помощью менеджера пакетов Composer в свой проект:
composer require laravel/scout
После установки Scout вы должны опубликовать конфигурационный файл Scout с помощью команды vendor:publish
Artisan. Эта команда опубликует конфигурационный файл scout.php
в каталоге config
вашего приложения:
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
Наконец, добавьте трейт Laravel\Scout\Searchable
модели, которую вы хотите сделать доступной для поиска. Этот трейт зарегистрирует наблюдателя модели, который будет автоматически синхронизировать модель с вашим драйвером поиска:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
}
При использовании драйвера Algolia вы должны указать свои учетные данные Algolia id
и secret
в конфигурационном файле config/scout.php
. После того, как ваши учетные данные будут указаны, вам также необходимо будет установить Algolia PHP SDK с помощью менеджера пакетов Composer:
composer require algolia/algoliasearch-client-php
MeiliSearch это невероятно быстрая поисковая система с открытым исходным кодом. Если вы не знаете, как установить MeiliSearch на свой локальный компьютер, то вы можете использовать Laravel Sail, официально поддерживаемая среда разработки Docker.
При использовании драйвера MeiliSearch вам необходимо установить PHP SDK MeiliSearch с помощью менеджера пакетов Composer:
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
Затем укажите переменную окружения SCOUT_DRIVER
, а также ваши учетные данные host
и key
MeiliSearch в файле .env
вашего приложения:
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=masterKey
Для получения дополнительной информации о MeiliSearch, пожалуйста, обратитесь к документации MeiliSearch.
Кроме того, вам следует убедиться, что вы установили версию meilisearch/meilisearch-php
, совместимую с вашей версией MeiliSearch, просмотрев документацию MeiliSearch о совместимости.
{note} При обновлении Scout в приложении, которое использует MeiliSearch, вы всегда должны просматривать любые дополнительные критические изменения в самой службе MeiliSearch.
Хотя это и не является строго обязательным, но вам следует подумать о настройке драйвера очереди перед использованием пакета Scout. Запуск обработчика очереди позволит Scout ставить в очередь все операции, которые синхронизируют информацию вашей модели с вашими поисковыми индексами, что обеспечивает гораздо лучшее время отклика для веб-интерфейса вашего приложения.
После того, как вы настроили драйвер очереди, установите значение true
для параметра queue
в вашем конфигурационном файле config/scout.php
:
'queue' => true,
Каждая модель Eloquent синхронизируется с конкретным поисковым «индексом», который содержит все доступные для поиска записи данной модели. Другими словами, вы можете думать о каждом индексе как о таблице MySQL. По умолчанию каждая модель будет сохранена в индексе, соответствующем типичному «табличному» имени модели. Обычно это форма множественного числа от названия модели; однако вы можете изменить индекс модели, переопределив метод searchableAs
модели:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
/**
* Получить имя индекса, связанного с моделью.
*
* @return string
*/
public function searchableAs()
{
return 'posts_index';
}
}
По умолчанию все результаты метода toArray
модели будут сохранены в поисковом индексе. Если вы хотите изменить синхронизируемые с поисковым индексом данные, то вы можете переопределить метод toSearchableArray
модели:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
/**
* Получить индексируемый массив данных модели.
*
* @return array
*/
public function toSearchableArray()
{
$array = $this->toArray();
// Изменение массива данных ...
return $array;
}
}
По умолчанию Scout будет использовать первичный ключ модели в качестве уникального идентификатора / ключа модели для сохранения в поисковом индексе. Если вам нужно изменить это поведение, то вы можете переопределить методы getScoutKey
и getScoutKeyName
модели:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class User extends Model
{
use Searchable;
/**
* Получить значение ключа, используемое для индексации модели.
*
* @return mixed
*/
public function getScoutKey()
{
return $this->email;
}
/**
* Получить имя ключа, используемое для индексации модели.
*
* @return mixed
*/
public function getScoutKeyName()
{
return 'email';
}
}
Scout также позволяет автоматически идентифицировать пользователей при использовании Algolia. Связывание аутентифицированного пользователя с операциями поиска может быть полезно при просмотре аналитики поиска в панели управления Algolia. Вы можете задействовать идентификацию пользователя, определив значение true
для переменной окружения SCOUT_IDENTIFY
в файле .env
вашего приложения:
SCOUT_IDENTIFY=true
С помощью данного функционала, дополнительно будет переданы IP-адрес запроса и основной идентификатор вашего аутентифицированного пользователя в Algolia, таким образом, эти данные будут связаны с любым поисковым запросом, сделанным пользователем.
Хотя вы можете использовать поисковые системы Algolia или MeiliSearch во время локальной разработки, вам может быть удобнее начать работу с поисковой системой collection
. Поисковая система будет использовать выражения where
и фильтрацию набора результатов из вашей существующей базы данных, чтобы определить подходящие результаты поиска по вашему запросу. При использовании этого системы нет необходимости «индексировать» ваши доступные для поиска модели, поскольку они будут просто извлечены из вашей локальной базы данных.
Чтобы использовать данную поисковую систему, вы можете просто установить для переменной окружения SCOUT_DRIVER
значение collection
или указать драйвер collection
непосредственно в конфигурационном файле scout
вашего приложения:
SCOUT_DRIVER=collection
После того, как вы указали драйвер collection
в качестве предпочтительного драйвера, вы можете начать выполнение поисковых запросов по вашим моделям. Индексирование поисковой системы, которое необходимо для заполнения Algolia или MeiliSearch, не требуется при использовании поисковой системы collection
.
Если вы устанавливаете Scout в существующий проект, то возможно, у вас уже есть записи базы данных, которые необходимо импортировать в соответствующие индексы. Scout содержит команду scout:import
Artisan, которую вы можете использовать для импорта всех ваших существующих записей в соответствующие поисковые индексы:
php artisan scout:import "App\Models\Post"
Команду flush
можно использовать для удаления всех записей модели из поисковых индексов:
php artisan scout:flush "App\Models\Post"
Если вы хотите изменить запрос, используемый для получения всех ваших моделей при пакетном импорте, то вы можете определить метод makeAllSearchableUsing
своей модели. Это отличное место для добавления любой нетерпеливой загрузки отношений, которая может потребоваться перед импортом ваших моделей:
/**
* Изменить запрос, используемый для получения всех индексируемых моделей.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function makeAllSearchableUsing($query)
{
return $query->with('author');
}
После добавления в модель трейта Laravel\Scout\Searchable
, все, что вам нужно сделать, это вызвать методы save
или create
экземпляра модели, и она будет автоматически добавлена в ваш поисковый индекс. Если вы настроили использование очередей, то эта операция будет выполняться в фоновом режиме вашим обработчиком очереди:
use App\Models\Order;
$order = new Order;
// ...
$order->save();
Если вы хотите добавить коллекцию моделей в поисковый индекс с помощью запроса Eloquent, то вы можете связать метод searchable
с запросом Eloquent. Метод searchable
разбивает результаты запроса и добавляет записи в поисковый индекс. Опять же, если вы настроили использование очередей, то все подмножества моделей будут импортированы в фоновом режиме вашим обработчиком очереди:
use App\Models\Order;
Order::where('price', '>', 100)->searchable();
Вы также можете вызвать метод searchable
экземпляра отношения Eloquent:
$user->orders()->searchable();
Или, если у вас уже имеется в наличии коллекция моделей Eloquent, то вы можете вызвать метод searchable
экземпляра коллекции, чтобы добавить экземпляры модели в соответствующий индекс:
$orders->searchable();
{tip} Метод
searchable
можно считать операцией «обновления-вставки». Другими словами, если запись модели уже есть в вашем индексе, то она будет обновлена. Если записи нет в поисковом индексе, то она будет добавлен в индекс.
Чтобы обновить модель в поиске, то вам нужно только обновить свойства экземпляра модели и вызвать метод save
модели. Scout автоматически сохранит изменения в вашем поисковом индексе:
use App\Models\Order;
$order = Order::find(1);
// Обновление заказа ...
$order->save();
Вы также можете вызвать метод searchable
экземпляра запроса Eloquent, чтобы обновить коллекцию моделей. Если моделей нет в поисковом индексе, то они будут созданы:
Order::where('price', '>', 100)->searchable();
Если вы хотите обновить записи поискового индекса для всех моделей отношения, то вы можете вызвать searchable
экземпляра отношения:
$user->orders()->searchable();
Или, если у вас уже имеется в наличии коллекция моделей Eloquent, то вы можете вызвать метод searchable
экземпляра коллекции, чтобы обновить экземпляры модели в соответствующем индексе:
$orders->searchable();
Чтобы удалить запись из поискового индекса с сопутствующим удалением из базы данных, то вы можете просто вызвать метод delete
модели. Это можно сделать, даже если вы используете программное удаление моделей:
use App\Models\Order;
$order = Order::find(1);
$order->delete();
Если вы не хотите извлекать модель перед удалением записи, то вы можете использовать метод unsearchable
экземпляра запроса Eloquent:
Order::where('price', '>', 100)->unsearchable();
Если вы хотите удалить записи поискового индекса для всех моделей в отношении, то вы можете вызвать unsearchable
экземпляра отношения:
$user->orders()->unsearchable();
Или, если у вас уже имеется в наличии коллекция моделей Eloquent, то вы можете вызвать метод unsearchable
экземпляра коллекции, чтобы удалить экземпляры модели из соответствующего индекса:
$orders->unsearchable();
Иногда требуется выполнить пакет действий Eloquent с моделью без синхронизации данных модели с поисковым индексом. Вы можете сделать это, используя метод withoutSyncingToSearch
. Этот метод принимает замыкание, которое будет немедленно выполнено. Любые операции модели, выполняемые внутри замыкания, не будут синхронизированы с поисковым индексом модели:
use App\Models\Order;
Order::withoutSyncingToSearch(function () {
// Выполнение действий с моделью ...
});
Иногда требуется сделать модель доступной для поиска только при определенных условиях. Например, представьте, что у вас есть модель поста App\Models\Post
, который может находиться в одном из двух состояний: «черновик» и «опубликован». Вы можете разрешить поиск только «опубликованных» постов. Для этого вы можете определить метод shouldBeSearchable
модели:
/**
* Определить, должна ли модель индексироваться.
*
* @return bool
*/
public function shouldBeSearchable()
{
return $this->isPublished();
}
Метод shouldBeSearchable
учитывается при манипулировании моделями через запросы, отношения или методы save
и create
. Непосредственное указание доступности моделей или коллекций для поиска с помощью метода searchable
переопределит результат метода shouldBeSearchable
.
Вы можете начать поиск модели, используя метод search
. Метод search
принимает одну строку, которая будет использоваться для поиска ваших моделей. Затем вы должны связать метод get
с поисковым запросом, чтобы получить модели Eloquent, соответствующие указанному поисковому запросу:
use App\Models\Order;
$orders = Order::search('Star Trek')->get();
Поскольку поисковые запросы Scout возвращают коллекцию моделей Eloquent, то вы даже можете возвращать результаты непосредственно из маршрута или контроллера, и они будут автоматически преобразованы в JSON:
use App\Models\Order;
use Illuminate\Http\Request;
Route::get('/search', function (Request $request) {
return Order::search($request->search)->get();
});
Если вы хотите получить необработанные результаты поиска до того, как они будут преобразованы в модели Eloquent, то вы можете использовать метод raw
:
$orders = Order::search('Star Trek')->raw();
Поисковые запросы обычно выполняются по индексу, указанному в методе searchableAs
модели. Однако вы можете использовать метод within
, чтобы указать необходимый поисковый индекс:
$orders = Order::search('Star Trek')
->within('tv_shows_popularity_desc')
->get();
Scout позволяет добавлять к поисковым запросам простые выражения WHERE
. В настоящее время эти выражения поддерживают только базовые проверки числового равенства и в первую очередь полезны для определения области поисковых запросов по идентификатору владельца:
use App\Models\Order;
$orders = Order::search('Star Trek')->where('user_id', 1)->get();
Вы можете использовать метод whereIn
, чтобы ограничить результаты заданным набором значений:
$orders = Order::search('Star Trek')->whereIn(
'status', ['paid', 'open']
)->get();
Поскольку поисковый индекс не является реляционной базой данных, более сложные выражения WHERE
в настоящее время не поддерживаются.
Помимо получения коллекции моделей, вы можете разбить результаты поиска постранично, используя метод paginate
. Этот метод вернет экземпляр Illuminate\Pagination\LengthAwarePaginator
, как если бы это был обычный постраничный запрос Eloquent:
use App\Models\Order;
$orders = Order::search('Star Trek')->paginate();
Вы можете указать, сколько моделей необходимо извлекать на каждой странице, передав их количество методу paginate
:
$orders = Order::search('Star Trek')->paginate(15);
Получив результаты, вы можете отобразить их, а также ссылки на страницы с помощью Blade, как если бы это был обычный постраничный запрос Eloquent:
<div class="container">
@foreach ($orders as $order)
{{ $order->price }}
@endforeach
</div>
{{ $orders->links() }}
Конечно, если вы хотите получить результаты постраничной разбивки в виде JSON, то вы можете вернуть экземпляр пагинатора прямо из маршрута или контроллера:
use App\Models\Order;
use Illuminate\Http\Request;
Route::get('/orders', function (Request $request) {
return Order::search($request->input('query'))->paginate(15);
});
Если ваши индексируемые модели поддерживают программное удаление и вам необходимо выполнять поиск по таким моделям, то установите значение true
для параметра soft_delete
конфигурационного файла config/scout.php
:
'soft_delete' => true,
Когда этот параметр конфигурации имеет значение true
, тогда Scout не будет удалять такие модели из поискового индекса. Вместо этого он установит скрытый атрибут __soft_deleted
для проиндексированной записи. Затем вы можете использовать методы withTrashed
или onlyTrashed
для взаимодействия с программно удаленными записями при поиске:
use App\Models\Order;
// Добавить удаленные записи при получении результатов ...
$orders = Order::search('Star Trek')->withTrashed()->get();
// Вывести только удаленные записи при получении результатов ...
$orders = Order::search('Star Trek')->onlyTrashed()->get();
{tip} Если модель будет окончательно удалена с помощью
forceDelete
, то Scout автоматически удалит ее из поискового индекса.
Если вам нужно выполнить расширенный поиск, доступный для поисковой системы, то вы можете передать замыкание в качестве второго аргумента методу search
. Например, вы можете использовать это замыкание, чтобы добавить данные о геолокации в параметры поиска до того, как поисковый запрос будет передан в Algolia:
use Algolia\AlgoliaSearch\SearchIndex;
use App\Models\Order;
Order::search(
'Star Trek',
function (SearchIndex $algolia, string $query, array $options) {
$options['body']['query']['bool']['filter']['geo_distance'] = [
'distance' => '1000km',
'location' => ['lat' => 36, 'lon' => 111],
];
return $algolia->search($query, $options);
}
)->get();
Если ни одна из встроенных поисковых систем Scout не соответствует вашим потребностям, то вы можете написать свою собственную поисковую систему и зарегистрировать ее в Scout. Ваша система должна расширять абстрактный класс Laravel\Scout\Engines\Engine
. Этот абстрактный класс содержит восемь методов, которые должны быть реализованы в вашей поисковой системе:
use Laravel\Scout\Builder;
abstract public function update($models);
abstract public function delete($models);
abstract public function search(Builder $builder);
abstract public function paginate(Builder $builder, $perPage, $page);
abstract public function mapIds($results);
abstract public function map(Builder $builder, $results, $model);
abstract public function getTotalCount($results);
abstract public function flush($model);
Вы можете просмотреть реализации этих методов в классе Laravel\Scout\Engines\AlgoliaEngine
. Этот класс предоставит вам хорошую отправную точку в изучении того, как можно реализовать каждый из этих методов в своей поисковой системе.
После реализации поисковой системы вы можете зарегистрировать ее в Scout, используя метод extend
менеджера поисковых систем Scout. Менеджер поисковых систем Scout может быть извлечен из контейнера служб Laravel. Вы должны вызвать метод extend
в методе boot
поставщика App\Providers\AppServiceProvider
или любого другого поставщика служб, используемого вашим приложением:
use App\ScoutExtensions\MySqlSearchEngine
use Laravel\Scout\EngineManager;
/**
* Загрузка любых служб приложения.
*
* @return void
*/
public function boot()
{
resolve(EngineManager::class)->extend('mysql', function () {
return new MySqlSearchEngine;
});
}
После регистрации вашей поисковой системы вы можете указать ее в параметре driver
конфигурационного файла config/scout.php
вашего приложения в качестве драйвера, используемого по умолчанию в Scout:
'driver' => 'mysql',
Если вы хотите определить собственный метод построителя поискового запроса Scout, то вы можете использовать метод macro
класса Laravel\Scout\Builder
. Как правило, вызов этого метода осуществляется в методе boot
одного из поставщиков служб вашего приложения:
use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;
use Laravel\Scout\Builder;
/**
* Загрузка любых служб приложения.
*
* @return void
*/
public function boot()
{
Builder::macro('count', function () {
return $this->engine()->getTotalCount(
$this->engine()->search($this)
);
});
}
Метод macro
принимает имя макрокоманды как свой первый аргумент и замыкание – как второй аргумент. Замыкание макрокоманды будет выполнено при вызове имени макрокоманды из реализации Laravel\Scout\Builder
:
use App\Models\Order;
Order::search('Star Trek')->count();