Laravel Scout

Вступ

Laravel Scout надає просте рішення на основі драйверів для додавання повнотекстового пошуку до ваших Eloquent моделей. Використовуючи спостерігачів моделей, Scout автоматично підтримуватиме ваші пошукові індекси в синхронізації з вашими Eloquent записами.

На даний момент Scout постачається з драйверами Algolia, Meilisearch, Typesense та MySQL / PostgreSQL (database). Крім того, Scout включає драйвер "collection", який призначений для використання в локальній розробці і не вимагає жодних зовнішніх залежностей або сторонніх сервісів. Більше того, написання власних драйверів є простим, і ви можете розширити Scout своїми власними реалізаціями пошуку.

Встановлення

Спочатку встановіть Scout через менеджер пакетів Composer:

composer require laravel/scout

Після встановлення Scout, ви повинні опублікувати файл конфігурації Scout, використовуючи команду Artisan vendor:publish. Ця команда опублікує файл конфігурації 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;
}

Черги

Хоча це не є строго обов'язковим для використання Scout, вам слід серйозно розглянути можливість налаштування драйвера черги перед використанням бібліотеки. Запуск робітника черги дозволить Scout ставити в чергу всі операції, які синхронізують інформацію вашої моделі з вашими пошуковими індексами, забезпечуючи набагато кращі часи відгуку для веб-інтерфейсу вашого застосунку.

Після того як ви налаштували драйвер черги, встановіть значення опції queue у вашому конфігураційному файлі config/scout.php на true:

'queue' => true,

Навіть коли опція queue встановлена на false, важливо пам'ятати, що деякі драйвери Scout, такі як Algolia та Meilisearch, завжди індексують записи асинхронно. Це означає, що навіть якщо операція індексації завершена у вашому Laravel-застосунку, сам пошуковий двигун може не відображати нові та оновлені записи негайно.

Щоб вказати з'єднання та чергу, які використовують ваші Scout завдання, ви можете визначити опцію конфігурації queue як масив:

'queue' => [
    'connection' => 'redis',
    'queue' => 'scout'
],

Звичайно, якщо ви налаштовуєте з'єднання та чергу, які використовують завдання Scout, вам слід запустити робітника черги для обробки завдань на цьому з'єднанні та черзі:

php artisan queue:work redis --queue=scout

Вимоги до драйвера

Algolia

Коли ви використовуєте драйвер Algolia, вам слід налаштувати ваші облікові дані Algolia id та secret у вашому конфігураційному файлі config/scout.php. Після того, як ваші облікові дані налаштовані, вам також потрібно встановити Algolia PHP SDK через менеджер пакетів компонувальник:

composer require algolia/algoliasearch-client-php

Meilisearch

Meilisearch — це надзвичайно швидкий та відкритий пошуковий двигун. Якщо ви не впевнені, як встановити Meilisearch на ваш локальний комп'ютер, ви можете скористатися Laravel Sail, офіційно підтримуваним середовищем розробки Docker від Laravel.

Коли ви використовуєте драйвер Meilisearch, вам потрібно буде встановити Meilisearch PHP SDK через менеджер пакетів Composer:

composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle

Потім встановіть змінну середовища SCOUT_DRIVER, а також ваші облікові дані Meilisearch host і key у файлі .env вашого застосунку:

SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=masterKey

Для отримання додаткової інформації про Meilisearch, будь ласка, зверніться до документації Meilisearch.

Крім того, ви повинні переконатися, що встановили версію meilisearch/meilisearch-php, яка сумісна з вашою версією бінарного файлу Meilisearch, переглянувши документацію Meilisearch щодо бінарної сумісності.

Коли ви оновлюєте Scout у застосунку, що використовує Meilisearch, завжди слід переглядати будь-які додаткові критичні зміни у самому сервісі Meilisearch.

Typesense

Typesense — це надшвидкий пошуковий двигун з відкритим кодом, який підтримує пошук за ключовими словами, семантичний пошук, гео-пошук та векторний пошук.

Ви можете розгорнути самостійно Typesense або використовувати Typesense Cloud.

Щоб почати використовувати Typesense з Scout, встановіть Typesense PHP SDK через менеджер пакетів компонувальник:

composer require typesense/typesense-php

Потім встановіть змінну середовища SCOUT_DRIVER, а також облікові дані вашого хоста Typesense та API ключа у файлі .env вашого застосунку:

SCOUT_DRIVER=typesense
TYPESENSE_API_KEY=masterKey
TYPESENSE_HOST=localhost

Якщо ви використовуєте Laravel Sail, можливо, вам потрібно буде налаштувати змінну середовища TYPESENSE_HOST відповідно до імені контейнера Docker. Ви також можете за бажанням вказати порт, шлях і протокол вашої установки:

TYPESENSE_PORT=8108
TYPESENSE_PATH=
TYPESENSE_PROTOCOL=http

Додаткові налаштування та визначення схем для ваших колекцій Typesense можна знайти у файлі конфігурації вашого застосунку config/scout.php. Для отримання додаткової інформації щодо Typesense, будь ласка, зверніться до документації Typesense.

Підготовка даних для зберігання в Typesense

Коли ви використовуєте Typesense, ваші моделі, що підлягають пошуку, повинні визначати метод toSearchableArray, який перетворює первинний ключ вашої моделі на рядок, а дату створення на UNIX timestamp:

/**
 * Отримати індексований масив даних для моделі.
 *
 * @return array<string, mixed>
 */
public function toSearchableArray(): array
{
    return array_merge($this->toArray(),[
        'id' => (string) $this->id,
        'created_at' => $this->created_at->timestamp,
    ]);
}

Ви також повинні визначити схеми колекцій Typesense у файлі config/scout.php вашого застосунку. Схема колекції описує типи даних кожного поля, яке можна шукати за допомогою Typesense. Для отримання додаткової інформації про всі доступні параметри схем, будь ласка, зверніться до документації Typesense.

Якщо вам потрібно змінити схему вашої колекції Typesense після її визначення, ви можете виконати scout:flush та scout:import, що видалить всі існуючі індексовані дані та відтворить схему. Або ви можете скористатися API Typesense для зміни схеми колекції без видалення будь-яких індексованих даних.

Якщо ваша модель, що підлягає пошуку, підтримує м'яке видалення, ви повинні визначити поле __soft_deleted у відповідній схемі Typesense моделі в конфігураційному файлі вашого застосунку config/scout.php:

User::class => [
    'collection-schema' => [
        'fields' => [
            // ...
            [
                'name' => '__soft_deleted',
                'type' => 'int32',
                'optional' => true,
            ],
        ],
    ],
],

Динамічні параметри пошуку

Typesense дозволяє динамічно змінювати ваші параметри пошуку під час виконання операції пошуку за допомогою методу options:

use App\Models\Todo;
 
Todo::search('Groceries')->options([
    'query_by' => 'title, description'
])->get();

Конфігурація

Налаштування Індексів Моделі

Кожна модель Eloquent синхронізується з певним пошуковим "індексом", який містить усі записи, що можна шукати для цієї моделі. Іншими словами, ви можете уявити кожен індекс як таблицю MySQL. За замовчуванням, кожна модель буде збережена в індексі, що відповідає типовій назві "таблиці" моделі. Зазвичай це множинна форма назви моделі; однак, ви можете налаштувати індекс моделі, перевизначивши метод searchableAs у моделі:

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
 
class Post extends Model
{
    use Searchable;
 
    /**
     * Отримати назву індексу, пов'язаного з моделлю.
     */
    public function searchableAs(): string
    {
        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<string, mixed>
     */
    public function toSearchableArray(): array
    {
        $array = $this->toArray();
 
        // Налаштуйте масив даних...
 
        return $array;
    }
}

Деякі пошукові системи, такі як Meilisearch, виконуватимуть операції фільтрації (>, < тощо) лише на даних правильного типу. Тому, використовуючи ці пошукові системи та налаштовуючи ваші дані для пошуку, ви повинні переконатися, що числові значення приведені до їх правильного типу:

public function toSearchableArray()
{
    return [
        'id' => (int) $this->id,
        'name' => $this->name,
        'price' => (float) $this->price,
    ];
}

Налаштування параметрів індексу (Algolia)

Іноді ви можете захотіти налаштувати додаткові параметри на ваших індексах Algolia. Хоча ви можете керувати цими параметрами через інтерфейс Algolia, іноді більш ефективно керувати бажаним станом конфігурації вашого індексу безпосередньо з файлу конфігурації вашого застосунку config/scout.php.

Цей підхід дозволяє розгортати ці налаштування через автоматизований конвеєр розгортання вашого застосунку, уникаючи ручної конфігурації та забезпечуючи узгодженість у різних середовищах. Ви можете налаштувати атрибути для фільтрації, ранжування, фасетування або будь-які інші підтримувані налаштування.

Щоб почати, додайте налаштування для кожного індексу у файл конфігурації вашого застосунку config/scout.php:

use App\Models\User;
use App\Models\Flight;
 
'algolia' => [
    'id' => env('ALGOLIA_APP_ID', ''),
    'secret' => env('ALGOLIA_SECRET', ''),
    'index-settings' => [
        User::class => [
            'searchableAttributes' => ['id', 'name', 'email'],
            'attributesForFaceting'=> ['filterOnly(email)'],
            // Інші поля налаштувань...
        ],
        Flight::class => [
            'searchableAttributes'=> ['id', 'destination'],
        ],
    ],
],

Якщо модель, що лежить в основі даного індексу, підтримує м'яке видалення і включена в масив index-settings, Scout автоматично включить підтримку фасетування для м'яко видалених моделей у цьому індексі. Якщо у вас немає інших атрибутів фасетування для визначення індексу моделі з м'яким видаленням, ви можете просто додати порожній запис до масиву index-settings для цієї моделі:

'index-settings' => [
    Flight::class => []
],

Після налаштування індексних параметрів вашого застосунку, ви повинні викликати команду Artisan scout:sync-index-settings. Ця команда повідомить Algolia про ваші поточні налаштування індексу. Для зручності, ви можете зробити цю команду частиною вашого процесу розгортання:

php artisan scout:sync-index-settings

Налаштування Фільтрованих Даних та Індексації (Meilisearch)

На відміну від інших драйверів Scout, Meilisearch вимагає попередньо визначити налаштування індексу пошуку, такі як атрибути, що можна фільтрувати, атрибути, що можна сортувати, і інші підтримувані поля налаштувань.

Атрибути для фільтрації - це будь-які атрибути, за якими ви плануєте фільтрувати при виклику методу Scout where, тоді як атрибути для сортування - це будь-які атрибути, за якими ви плануєте сортувати при виклику методу Scout orderBy. Щоб визначити налаштування вашого індексу, відкоригуйте частину index-settings у записі конфігурації meilisearch у файлі конфігурації scout вашого застосунку:

use App\Models\User;
use App\Models\Flight;
 
'meilisearch' => [
    'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
    'key' => env('MEILISEARCH_KEY', null),
    'index-settings' => [
        User::class => [
            'filterableAttributes'=> ['id', 'name', 'email'],
            'sortableAttributes' => ['created_at'],
            // Інші поля налаштувань...
        ],
        Flight::class => [
            'filterableAttributes'=> ['id', 'destination'],
            'sortableAttributes' => ['updated_at'],
        ],
    ],
],

Якщо модель, що лежить в основі даного індексу, підтримує м'яке видалення і включена в масив index-settings, Scout автоматично включить підтримку фільтрації за м'яко видаленими моделями в цьому індексі. Якщо у вас немає інших атрибутів для фільтрації або сортування, які потрібно визначити для індексу моделі з м'яким видаленням, ви можете просто додати порожній запис до масиву index-settings для цієї моделі:

'index-settings' => [
    Flight::class => []
],

Після налаштування параметрів індексу вашого застосунку, ви повинні викликати команду Artisan scout:sync-index-settings. Ця команда повідомить Meilisearch про ваші поточні налаштування індексу. Для зручності, ви можете зробити цю команду частиною вашого процесу розгортання:

php artisan scout:sync-index-settings

Налаштування ID моделі

За замовчуванням Scout використовуватиме первинний ключ моделі як унікальний ID / ключ моделі, що зберігається в індексі пошуку. Якщо вам потрібно налаштувати цю поведінку, ви можете перевизначити методи getScoutKey та getScoutKeyName у моделі:

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
 
class User extends Model
{
    use Searchable;
 
    /**
     * Отримати значення, яке використовується для індексації моделі.
     */
    public function getScoutKey(): mixed
    {
        return $this->email;
    }
 
    /**
     * Отримати ім'я ключа, яке використовується для індексації моделі.
     */
    public function getScoutKeyName(): mixed
    {
        return 'email';
    }
}

Налаштування пошукових систем для кожної моделі

Коли виконується пошук, Scout зазвичай використовуватиме пошукову систему за замовчуванням, вказану у файлі конфігурації scout вашого застосунку. Однак, пошукову систему для конкретної моделі можна змінити, перевизначивши метод searchableUsing у моделі:

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Engines\Engine;
use Laravel\Scout\EngineManager;
use Laravel\Scout\Searchable;
 
class User extends Model
{
    use Searchable;
 
    /**
     * Отримати механізм, який використовується для індексації моделі.
     */
    public function searchableUsing(): Engine
    {
        return app(EngineManager::class)->engine('meilisearch');
    }
}

Ідентифікація користувачів

Scout також дозволяє автоматично ідентифікувати користувачів при використанні Algolia. Асоціювання автентифікованого користувача з операціями пошуку може бути корисним при перегляді вашої аналітики пошуку в панелі керування Algolia. Ви можете увімкнути ідентифікацію користувачів, визначивши змінну середовища SCOUT_IDENTIFY як true у файлі .env вашого застосунку:

SCOUT_IDENTIFY=true

Увімкнення цієї функції також передасть IP-адресу запиту та основний ідентифікатор автентифікованого користувача до Algolia, щоб ці дані були пов'язані з будь-яким пошуковим запитом, зробленим користувачем.

Бази даних / Двигуни колекцій

Двигун бази даних

Двигун бази даних наразі підтримує MySQL та PostgreSQL.

Якщо ваш застосунок взаємодіє з малими або середніми базами даних або має легке навантаження, ви можете знайти більш зручним почати з "database" двигуна Scout. Двигун database буде використовувати "where like" клаузи та повнотекстові індекси при фільтрації результатів з вашої існуючої бази даних для визначення відповідних результатів пошуку для вашого запиту.

Щоб використовувати механізм бази даних, ви можете просто встановити значення змінної середовища SCOUT_DRIVER на database, або вказати драйвер database безпосередньо у файлі конфігурації scout вашого застосунку:

SCOUT_DRIVER=database

Після того як ви вказали базу даних як ваш бажаний драйвер, ви повинні налаштувати ваші дані для пошуку. Потім ви можете почати виконувати пошукові запити до ваших моделей. Індексація пошукової системи, така як індексація, необхідна для заповнення індексів Algolia, Meilisearch або Typesense, не потрібна при використанні бази даних.

Налаштування стратегій пошуку в базі даних

За замовчуванням, рушій бази даних виконуватиме запит "where like" для кожного атрибута моделі, який ви налаштували як доступний для пошуку. Однак у деяких ситуаціях це може призвести до низької продуктивності. Тому стратегію пошуку рушія бази даних можна налаштувати так, щоб деякі вказані стовпці використовували запити повнотекстового пошуку або лише використовували обмеження "where like" для пошуку префіксів рядків (example%) замість пошуку в межах усього рядка (%example%).

Щоб визначити цю поведінку, ви можете призначити атрибути PHP методу toSearchableArray вашої моделі. Будь-які стовпці, яким не призначено додаткову поведінку стратегії пошуку, продовжуватимуть використовувати стандартну стратегію "where like":

use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;
 
/**
 * Отримати індексований масив даних для моделі.
 *
 * @return array<string, mixed>
 */
#[SearchUsingPrefix(['id', 'email'])]
#[SearchUsingFullText(['bio'])]
public function toSearchableArray(): array
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'bio' => $this->bio,
    ];
}

Перш ніж вказати, що стовпець повинен використовувати обмеження повнотекстового запиту, переконайтеся, що стовпцю призначено повнотекстовий індекс.

Двигун Колекцій

Хоча ви можете вільно використовувати пошукові системи Algolia, Meilisearch або Typesense під час локальної розробки, вам може бути зручніше почати з "collection" engine. Collection engine буде використовувати "where" умови та фільтрацію колекцій на результатах з вашої існуючої бази даних для визначення відповідних результатів пошуку для вашого запиту. При використанні цього engine, немає необхідності "індексувати" ваші моделі для пошуку, оскільки вони просто будуть отримані з вашої локальної бази даних.

Щоб використовувати механізм колекцій, ви можете просто встановити значення змінної середовища SCOUT_DRIVER на collection, або вказати драйвер collection безпосередньо у файлі конфігурації scout вашого застосунку:

SCOUT_DRIVER=collection

Після того як ви вказали колекційний драйвер як ваш улюблений драйвер, ви можете почати виконувати пошукові запити до ваших моделей. Індексація пошукових систем, така як індексація, необхідна для заповнення індексів Algolia, Meilisearch або Typesense, не потрібна при використанні колекційного двигуна.

Відмінності від СУБД

На перший погляд, "database" та "collections" рушії досить схожі. Вони обидва взаємодіють безпосередньо з вашою базою даних для отримання результатів пошуку. Однак, рушій collections не використовує повнотекстові індекси або LIKE вирази для пошуку відповідних записів. Натомість, він витягує всі можливі записи та використовує хелпер Laravel Str::is для визначення, чи існує рядок пошуку в значеннях атрибутів моделі.

Колекційний двигун є найбільш портативним пошуковим двигуном, оскільки він працює з усіма реляційними базами даних, які підтримуються Laravel (включаючи SQLite та SQL Server); однак, він менш ефективний, ніж базовий двигун Scout.

Індексація

Імпорт Пакету

Якщо ви встановлюєте Scout у вже існуючий проект, можливо, у вас вже є записи в базі даних, які потрібно імпортувати у ваші індекси. Scout надає команду Artisan scout:import, яку ви можете використовувати для імпорту всіх ваших існуючих записів у ваші пошукові індекси:

php artisan scout:import "App\Models\Post"

Команда flush може бути використана для видалення всіх записів моделі з ваших пошукових індексів:

php artisan scout:flush "App\Models\Post"

Зміна Запиту Імпорту

Якщо ви хочете змінити запит, який використовується для отримання всіх ваших моделей для пакетного імпорту, ви можете визначити метод makeAllSearchableUsing у вашій моделі. Це чудове місце для додавання будь-якого завантаження відносин, яке може бути необхідним перед імпортом ваших моделей:

use Illuminate\Database\Eloquent\Builder;
 
/**
 * Змініть запит, що використовується для отримання моделей, коли робите всі моделі доступними для пошуку.
 */
protected function makeAllSearchableUsing(Builder $query): Builder
{
    return $query->with('author');
}

Метод makeAllSearchableUsing може бути непридатним при використанні черги для пакетного імпорту моделей. Відносини не відновлюються, коли колекції моделей обробляються завданнями.

Додавання записів

Після того як ви додали трейта Laravel\Scout\Searchable до моделі, все, що вам потрібно зробити, це save або create екземпляр моделі, і він автоматично буде доданий до вашого пошукового індексу. Якщо ви налаштували Scout на використання черг, ця операція буде виконана у фоновому режимі вашим працівником черги:

use App\Models\Order;
 
$order = new Order;
 
// ...
 
$order->save();

Додавання записів через запит

Якщо ви хочете додати колекцію моделей до вашого пошукового індексу через запит Eloquent, ви можете приєднати метод searchable до запиту Eloquent. Метод searchable буде розбивати результати запиту на частини та додавати записи до вашого пошукового індексу. Знову ж таки, якщо ви налаштували Scout для використання черг, всі частини будуть імпортовані у фоновому режимі вашими працівниками черги:

use App\Models\Order;
 
Order::where('price', '>', 100)->searchable();

Ви також можете викликати метод searchable на екземплярі відношення Eloquent:

$user->orders()->searchable();

Або, якщо у вас вже є колекція моделей Eloquent у пам'яті, ви можете викликати метод searchable на екземплярі колекції, щоб додати екземпляри моделей до їх відповідного індексу:

$orders->searchable();

Метод searchable можна вважати операцією "upsert". Іншими словами, якщо запис моделі вже є у вашому індексі, він буде оновлений. Якщо його немає в індексі пошуку, він буде доданий до індексу.

Оновлення записів

Щоб оновити модель, що підлягає пошуку, вам потрібно лише оновити властивості екземпляра моделі та зберегти модель у вашу базу даних. 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();

Модифікація записів перед імпортом

Іноді вам може знадобитися підготувати колекцію моделей перед тим, як вони стануть доступними для пошуку. Наприклад, ви можете захотіти завантажити відношення заздалегідь, щоб дані відношення могли бути ефективно додані до вашого пошукового індексу. Щоб досягти цього, визначте метод makeSearchableUsing у відповідній моделі:

use Illuminate\Database\Eloquent\Collection;
 
/**
 * Змініть колекцію моделей, які робляться доступними для пошуку.
 */
public function makeSearchableUsing(Collection $models): Collection
{
    return $models->load('author');
}

Видалення записів

Щоб видалити запис з вашого індексу, ви можете просто видалити модель з бази даних. Це можна зробити, навіть якщо ви використовуєте м'яке видалення моделей:

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();

Щоб видалити всі записи моделі з їх відповідного індексу, ви можете викликати метод removeAllFromSearch:

Order::removeAllFromSearch();

Призупинення Індексації

Іноді вам може знадобитися виконати пакет операцій Eloquent на моделі без синхронізації даних моделі з вашим пошуковим індексом. Ви можете зробити це за допомогою методу withoutSyncingToSearch. Цей метод приймає одну замикання, яке буде виконано негайно. Будь-які операції з моделлю, що відбуваються в межах замикання, не будуть синхронізовані з індексом моделі:

use App\Models\Order;
 
Order::withoutSyncingToSearch(function () {
    // Виконання дій моделі...
});

Умовно Пошукові Екземпляри Моделей

Іноді вам може знадобитися зробити модель доступною для пошуку лише за певних умов. Наприклад, уявіть, що у вас є модель App\Models\Post, яка може бути в одному з двох станів: "draft" і "published". Ви можете захотіти дозволити пошук лише для "published" постів. Щоб досягти цього, ви можете визначити метод shouldBeSearchable у вашій моделі:

/**
 * Визначити, чи має модель бути доступною для пошуку.
 */
public function shouldBeSearchable(): bool
{
    return $this->isPublished();
}

Метод shouldBeSearchable застосовується лише при маніпуляціях з моделями через методи save і create, запити або відносини. Безпосереднє використання моделей або колекцій для пошуку за допомогою методу searchable перевизначить результат методу shouldBeSearchable.

Метод shouldBeSearchable не застосовується при використанні "database" двигуна Scout, оскільки всі дані, що підлягають пошуку, завжди зберігаються в базі даних. Щоб досягти подібної поведінки при використанні database двигуна, слід використовувати where clauses замість цього.

Пошук

Ви можете почати пошук моделі, використовуючи метод 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();

Умова where

Scout дозволяє додавати прості "where" умови до ваших пошукових запитів. Наразі ці умови підтримують лише базові перевірки числової рівності і в основному корисні для обмеження пошукових запитів за ID власника:

use App\Models\Order;
 
$orders = Order::search('Star Trek')->where('user_id', 1)->get();

Крім того, метод whereIn може бути використаний для перевірки, що значення заданої колонки міститься в заданому масиві:

$orders = Order::search('Star Trek')->whereIn(
    'status', ['open', 'paid']
)->get();

Метод whereNotIn перевіряє, що значення вказаного стовпця не міститься у вказаному масиві:

$orders = Order::search('Star Trek')->whereNotIn(
    'status', ['closed']
)->get();

Оскільки індекс пошуку не є реляційною базою даних, більш складні оператори "where" наразі не підтримуються.

Якщо ваш застосунок використовує Meilisearch, ви повинні налаштувати атрибути для фільтрації вашого застосунку перед використанням "where" умов Scout.

Пагінація

Крім отримання колекції моделей, ви можете здійснити пагінацію результатів пошуку за допомогою методу 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);
});

Оскільки пошукові системи не знають про визначення глобальної області вашої моделі Eloquent, ви не повинні використовувати глобальні області в застосунках, які використовують пагінацію Scout. Або ж ви повинні відтворити обмеження глобальної області при пошуку через Scout.

М'яке видалення

Якщо ваші індексовані моделі м'яко видаляються і вам потрібно шукати ваші м'яко видалені моделі, встановіть опцію soft_delete у файлі конфігурації config/scout.php на true:

'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();

Коли модель, що була м'яко видалена, видаляється назавжди за допомогою 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();

Налаштування запиту результатів Eloquent

Після того як Scout отримує список відповідних моделей Eloquent з пошукової системи вашого застосунку, Eloquent використовується для отримання всіх відповідних моделей за їхніми первинними ключами. Ви можете налаштувати цей запит, викликавши метод query. Метод query приймає замикання, яке отримає екземпляр конструктора запитів Eloquent як аргумент:

use App\Models\Order;
use Illuminate\Database\Eloquent\Builder;
 
$orders = Order::search('Star Trek')
    ->query(fn (Builder $query) => $query->with('invoices'))
    ->get();

Оскільки цей зворотний виклик викликається після того, як відповідні моделі вже були отримані з пошукової системи вашого застосунку, метод query не слід використовувати для "фільтрації" результатів. Натомість, слід використовувати Scout where clauses.

Користувацькі двигуни

Створення двигуна

Якщо жоден з вбудованих пошукових двигунів 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;
 
/**
 * Завантажте будь-які сервіси застосунку.
 */
public function boot(): void
{
    resolve(EngineManager::class)->extend('mysql', function () {
        return new MySqlSearchEngine;
    });
}

Після того як ваш двигун було зареєстровано, ви можете вказати його як ваш драйвер за замовчуванням для Scout у файлі конфігурації вашого застосунку config/scout.php:

'driver' => 'mysql',