Laravel Scout
はじめに
Laravel Scout は、Eloquentモデル にフルテキスト検索を追加するための、シンプルでドライバベースのソリューションを提供します。モデルオブザーバーを使用して、ScoutはEloquentレコードと検索インデックスを自動的に同期状態に保ちます。
現在、ScoutにはAlgolia、Meilisearch、Typesense、およびMySQL/PostgreSQL (database
) ドライバが付属しています。さらに、Scoutにはローカル開発用途向けに設計された「コレクション」ドライバが含まれており、外部依存関係やサードパーティサービスを必要としません。また、カスタムドライバの作成も簡単で、独自の検索実装でScoutを拡張できます。
インストール
まず、Composerパッケージマネージャーを使用してScoutをインストールします。
composer require laravel/scout
Scoutをインストールしたら、vendor:publish
Artisanコマンドを使用してScout設定ファイルを公開する必要があります。このコマンドは、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はモデル情報を検索インデックスに同期するすべての操作をキューに格納できるため、アプリケーションのWebインターフェースの応答時間が大幅に向上します。
キュードライバを設定したら、config/scout.php
設定ファイルのqueue
オプションの値をtrue
に設定します。
'queue' => true,
queue
オプションがfalse
に設定されている場合でも、AlgoliaやMeilisearchなどのScoutドライバの中には、常に非同期的にレコードをインデックスするものが存在することに注意することが重要です。つまり、インデックス操作がLaravelアプリケーション内で完了していても、検索エンジン自体には新しいレコードと更新されたレコードがすぐに反映されない可能性があります。
Scoutジョブが使用する接続とキューを指定するには、queue
設定オプションを配列として定義できます。
'queue' => [ 'connection' => 'redis', 'queue' => 'scout'],
もちろん、Scoutジョブが使用する接続とキューをカスタマイズする場合は、その接続とキューでジョブを処理するキューワーカーを実行する必要があります。
php artisan queue:work redis --queue=scout
ドライバの前提条件
Algolia
Algoliaドライバを使用する場合は、config/scout.php
設定ファイルでAlgoliaのid
とsecret
資格情報を設定する必要があります。資格情報を設定したら、Composerパッケージマネージャーを使用してAlgolia PHP SDKをインストールする必要があります。
composer require algolia/algoliasearch-client-php
Meilisearch
Meilisearch は、非常に高速でオープンソースの検索エンジンです。ローカルマシンにMeilisearchをインストールする方法がわからない場合は、Laravelの公式サポートされているDocker開発環境であるLaravel Sailを使用できます。
Meilisearchドライバを使用する場合は、Composerパッケージマネージャーを使用してMeilisearch PHP SDKをインストールする必要があります。
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
次に、アプリケーションの.env
ファイル内でSCOUT_DRIVER
環境変数とMeilisearchのhost
およびkey
資格情報を設定します。
SCOUT_DRIVER=meilisearchMEILISEARCH_HOST=http://127.0.0.1:7700MEILISEARCH_KEY=masterKey
Meilisearchの詳細については、Meilisearchのドキュメントを参照してください。
さらに、Meilisearchのバイナリ互換性に関するドキュメントを確認して、Meilisearchバイナリバージョンと互換性のあるバージョンのmeilisearch/meilisearch-php
をインストールしてください。
Meilisearchを使用するアプリケーションでScoutをアップグレードする際には、常にMeilisearchサービス自体の追加の破壊的変更を確認する必要があります。
Typesense
Typesense は、非常に高速なオープンソースの検索エンジンであり、キーワード検索、意味検索、ジオ検索、ベクトル検索をサポートしています。
自己ホスティングするか、Typesense Cloudを使用できます。
ScoutでTypesenseの使用を開始するには、Composerパッケージマネージャーを使用してTypesense PHP SDKをインストールします。
composer require typesense/typesense-php
次に、アプリケーションの.envファイル内でSCOUT_DRIVER
環境変数とTypesenseのホストとAPIキーの資格情報を設定します。
SCOUT_DRIVER=typesenseTYPESENSE_API_KEY=masterKeyTYPESENSE_HOST=localhost
Laravel Sailを使用している場合は、Dockerコンテナ名と一致するようにTYPESENSE_HOST
環境変数を調整する必要がある場合があります。必要に応じて、インストールのポート、パス、プロトコルを指定することもできます。
TYPESENSE_PORT=8108TYPESENSE_PATH=TYPESENSE_PROTOCOL=http
Typesenseコレクションの追加の設定とスキーマ定義は、アプリケーションのconfig/scout.php
設定ファイルにあります。Typesenseの詳細については、Typesenseのドキュメントを参照してください。
Typesenseへのデータ保存の準備
Typesenseを使用する場合、検索可能なモデルは、モデルの主キーを文字列に、作成日をUNIXタイムスタンプにキャストするtoSearchableArray
メソッドを定義する必要があります。
/** * Get the indexable data array for the model. * * @return array<string, mixed> */public function toSearchableArray(){ return array_merge($this->toArray(),[ 'id' => (string) $this->id, 'created_at' => $this->created_at->timestamp, ]);}
アプリケーションのconfig/scout.php
ファイルでTypesenseコレクションスキーマも定義する必要があります。コレクションスキーマは、Typesenseを介して検索可能な各フィールドのデータ型を記述します。使用可能なすべてのスキーマオプションの詳細については、Typesenseのドキュメントを参照してください。
定義後にTypesenseコレクションのスキーマを変更する必要がある場合は、scout:flush
とscout:import
を実行して、既存のインデックスデータをすべて削除し、スキーマを再作成するか、TypesenseのAPIを使用してインデックスデータを削除せずにコレクションのスキーマを変更できます。
検索可能なモデルがソフト削除可能な場合は、アプリケーションのconfig/scout.php
設定ファイル内のモデルに対応するTypesenseスキーマに__soft_deleted
フィールドを定義する必要があります。
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; /** * Get the name of the index associated with the model. */ 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; /** * Get the indexable data array for the model. * * @return array<string, mixed> */ public function toSearchableArray(): array { $array = $this->toArray(); // Customize the data array... return $array; }}
Meilisearchなどの検索エンジンは、正しい型のデータに対してのみフィルター操作(>
、<
など)を実行します。そのため、これらの検索エンジンを使用し、検索可能データをカスタマイズする場合は、数値が正しい型にキャストされていることを確認する必要があります。
public function toSearchableArray(){ return [ 'id' => (int) $this->id, 'name' => $this->name, 'price' => (float) $this->price, ];}
フィルター可能なデータとインデックス設定の設定 (Meilisearch)
Scoutの他のドライバとは異なり、Meilisearchでは、フィルタ可能な属性、ソート可能な属性、およびその他のサポートされている設定フィールドなど、インデックス検索設定を事前に定義する必要があります。
フィルタ可能な属性とは、Scoutのwhere
メソッドを呼び出す際にフィルタリングする予定の属性であり、ソート可能な属性とは、ScoutのorderBy
メソッドを呼び出す際にソートする予定の属性です。インデックス設定を定義するには、アプリケーションのscout
設定ファイル内のmeilisearch
設定エントリのindex-settings
部分を調整します。
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'], // Other settings fields... ], Flight::class => [ 'filterableAttributes'=> ['id', 'destination'], 'sortableAttributes' => ['updated_at'], ], ],],
特定のインデックスの基になるモデルがソフトデリート可能であり、index-settings
配列に含まれている場合、Scoutは自動的にそのインデックス上のソフトデリートされたモデルのフィルタリングをサポートします。ソフトデリート可能なモデルインデックスに対して定義する他のフィルタ可能な属性またはソート可能な属性がない場合は、そのモデルのindex-settings
配列に空のエントリを追加するだけで済みます。
'index-settings' => [ Flight::class => []],
アプリケーションのインデックス設定を構成したら、scout:sync-index-settings
Artisanコマンドを呼び出す必要があります。このコマンドは、現在構成されているインデックス設定を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; /** * Get the value used to index the model. */ public function getScoutKey(): mixed { return $this->email; } /** * Get the key name used to index the model. */ 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; /** * Get the engine used to index the model. */ public function searchableUsing(): Engine { return app(EngineManager::class)->engine('meilisearch'); }}
ユーザーの識別
Scoutでは、Algoliaを使用する場合にも、ユーザーを自動的に識別できます。認証されたユーザーを検索操作に関連付けることは、Algoliaのダッシュボードで検索分析を表示する際に役立つ場合があります。ユーザー識別を有効にするには、アプリケーションの.env
ファイルでSCOUT_IDENTIFY
環境変数をtrue
として定義します。
SCOUT_IDENTIFY=true
この機能を有効にすると、リクエストのIPアドレスと認証済みユーザーのプライマリ識別子がAlgoliaに渡されるため、このデータはユーザーによって行われたすべての検索リクエストに関連付けられます。
データベース/コレクションエンジン
データベースエンジン
データベースエンジンは現在、MySQLとPostgreSQLをサポートしています。
アプリケーションが小規模から中規模のデータベースとやり取りする場合、またはワークロードが軽い場合は、Scoutの「database」エンジンから始める方が便利な場合があります。「database」エンジンは、「where like」句と全文インデックスを使用して、既存のデータベースから結果をフィルタリングし、クエリに適用可能な検索結果を決定します。
データベースエンジンを使用するには、SCOUT_DRIVER
環境変数の値をdatabase
に設定するか、アプリケーションのscout
設定ファイルでdatabase
ドライバを直接指定するだけです。
SCOUT_DRIVER=database
データベースエンジンを優先ドライバとして指定したら、検索可能なデータの構成を行う必要があります。その後、モデルに対して検索クエリの実行を開始できます。Algolia、Meilisearch、Typesenseのインデックスをシードするために必要なインデックス作成など、検索エンジンのインデックス作成は、データベースエンジンを使用する場合は不要です。
データベース検索戦略のカスタマイズ
デフォルトでは、データベースエンジンは、検索可能として構成されているすべてのモデル属性に対して「where like」クエリを実行します。ただし、状況によっては、これによりパフォーマンスが低下する可能性があります。そのため、データベースエンジンの検索戦略を構成して、指定された列で全文検索クエリを使用するか、文字列全体内を検索する代わりに(%example%
)、文字列の先頭のみを検索する(example%
)「where like」制約のみを使用するようにできます。
この動作を定義するには、モデルのtoSearchableArray
メソッドにPHP属性を割り当てることができます。追加の検索戦略動作が割り当てられていない列は、引き続きデフォルトの「where like」戦略を使用します。
use Laravel\Scout\Attributes\SearchUsingFullText;use Laravel\Scout\Attributes\SearchUsingPrefix; /** * Get the indexable data array for the model. * * @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」エンジンから始める方が便利な場合があります。「collection」エンジンは、「where」句とコレクションフィルタリングを使用して、既存のデータベースから結果を取得し、クエリに適用可能な検索結果を決定します。このエンジンを使用する場合、検索可能なモデルを「インデックス」する必要はありません。ローカルデータベースから取得されるだけです。
コレクションエンジンを使用するには、SCOUT_DRIVER
環境変数の値をcollection
に設定するか、アプリケーションのscout
設定ファイルでcollection
ドライバを直接指定するだけです。
SCOUT_DRIVER=collection
コレクションドライバを優先ドライバとして指定したら、モデルに対して検索クエリの実行を開始できます。Algolia、Meilisearch、Typesenseのインデックスをシードするために必要なインデックス作成など、検索エンジンのインデックス作成は、コレクションエンジンを使用する場合は不要です。
データベースエンジンとの違い
一見、「database」エンジンと「collections」エンジンは非常に似ています。どちらもデータベースと直接やり取りして検索結果を取得します。ただし、コレクションエンジンは、一致するレコードを見つけるために全文インデックスまたはLIKE
句を使用しません。代わりに、可能なすべてのレコードを取得し、LaravelのStr::is
ヘルパーを使用して、検索文字列がモデル属性値内に存在するかどうかを判断します。
コレクションエンジンは、Laravelでサポートされているすべてのリレーショナルデータベース(SQLiteやSQL Serverを含む)で動作するため、最も移植性の高い検索エンジンですが、Scoutのデータベースエンジンよりも効率性が低くなります。
インデックス作成
一括インポート
既存のプロジェクトにScoutをインストールする場合、インデックスにインポートする必要があるデータベースレコードが既に存在する可能性があります。Scoutは、既存のレコードをすべて検索インデックスにインポートするために使用できるscout:import
Artisanコマンドを提供しています。
php artisan scout:import "App\Models\Post"
flush
コマンドを使用して、モデルのレコードをすべて検索インデックスから削除できます。
php artisan scout:flush "App\Models\Post"
インポートクエリの変更
バッチインポートのためにモデルのすべてを取得するために使用されるクエリを変更する場合は、モデルでmakeAllSearchableUsing
メソッドを定義できます。これは、モデルのインポート前に必要なエンシュアードリレーションロードを追加するのに最適な場所です。
use Illuminate\Database\Eloquent\Builder; /** * Modify the query used to retrieve models when making all of the models searchable. */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クエリを使用してモデルのコレクションを検索インデックスに追加する場合は、Eloquentクエリにsearchable
メソッドをチェーンできます。searchable
メソッドは、クエリの結果をチャンク化し、レコードを検索インデックスに追加します。繰り返しますが、Scoutがキューを使用するように構成されている場合、すべてのチャンクはバックグラウンドでキューワーカーによってインポートされます。
use App\Models\Order; Order::where('price', '>', 100)->searchable();
Eloquentリレーションシップインスタンスにもsearchable
メソッドを呼び出すことができます。
$user->orders()->searchable();
あるいは、既にメモリにEloquentモデルのコレクションがある場合は、コレクションインスタンスでsearchable
メソッドを呼び出して、モデルインスタンスを対応するインデックスに追加できます。
$orders->searchable();
searchable
メソッドは「upsert」操作と考えることができます。つまり、モデルレコードが既にインデックスにある場合は更新され、検索インデックスに存在しない場合はインデックスに追加されます。
レコードの更新
検索可能なモデルを更新するには、モデルインスタンスのプロパティを更新して、モデルをデータベースにsave
するだけです。Scoutは、検索インデックスへの変更を自動的に永続化します。
use App\Models\Order; $order = Order::find(1); // Update the order... $order->save();
Eloquentクエリインスタンスでsearchable
メソッドを呼び出して、モデルのコレクションを更新することもできます。モデルが検索インデックスに存在しない場合は、作成されます。
Order::where('price', '>', 100)->searchable();
リレーションシップ内のすべてのモデルの検索インデックスレコードを更新する場合は、リレーションシップインスタンスでsearchable
を呼び出すことができます。
$user->orders()->searchable();
あるいは、既にメモリにEloquentモデルのコレクションがある場合は、コレクションインスタンスでsearchable
メソッドを呼び出して、対応するインデックス内のモデルインスタンスを更新できます。
$orders->searchable();
インポート前のレコードの変更
検索可能になる前にモデルのコレクションを準備する必要がある場合があります。たとえば、リレーションシップデータを効率的に検索インデックスに追加するために、リレーションシップをエンシュアードロードする必要がある場合があります。これを実現するには、対応するモデルでmakeSearchableUsing
メソッドを定義します。
use Illuminate\Database\Eloquent\Collection; /** * Modify the collection of models being made searchable. */public function makeSearchableUsing(Collection $models): Collection{ return $models->load('author');}
レコードの削除
インデックスからレコードを削除するには、データベースからモデルをdelete
するだけです。ソフトデリートされたモデルを使用している場合でも、これを行うことができます。
use App\Models\Order; $order = Order::find(1); $order->delete();
レコードを削除する前にモデルを取得したくない場合は、Eloquentクエリインスタンスでunsearchable
メソッドを使用できます。
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 () { // Perform model actions...});
条件付きで検索可能なモデルインスタンス
特定の条件下でのみモデルを検索可能にする必要がある場合があります。たとえば、「draft」と「published」の2つの状態のいずれかにある可能性のあるApp\Models\Post
モデルがあるとします。「published」の投稿のみを検索可能にしたい場合があります。これを実現するには、モデルでshouldBeSearchable
メソッドを定義します。
/** * Determine if the model should be searchable. */public function shouldBeSearchable(): bool{ return $this->isPublished();}
shouldBeSearchable
メソッドは、save
メソッドとcreate
メソッド、クエリ、またはリレーションシップを介してモデルを操作する場合にのみ適用されます。searchable
メソッドを使用してモデルまたはコレクションを直接検索可能にすることは、shouldBeSearchable
メソッドの結果をオーバーライドします。
Scoutの"database"エンジンを使用している場合、shouldBeSearchable
メソッドは適用できません。すべての検索可能なデータは常にデータベースに保存されるためです。データベースエンジンを使用する場合に同様の動作を実現するには、代わりにwhere句を使用してください。
検索
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を使用している場合は、Scoutの「where」句を使用する前に、アプリケーションのフィルタ可能な属性を構成する必要があります。
ページネーション
モデルのコレクションを取得することに加えて、paginate
メソッドを使用して検索結果をページ分割できます。このメソッドは、従来のEloquentクエリをページ分割した場合と同様に、Illuminate\Pagination\LengthAwarePaginator
インスタンスを返します。
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で検索する際にグローバルスコープの制約を再作成する必要があります。
ソフト削除
インデックス付きモデルがソフト削除されており、ソフト削除されたモデルを検索する必要がある場合は、config/scout.php
構成ファイルのsoft_delete
オプションをtrue
に設定します。
'soft_delete' => true,
この構成オプションがtrue
の場合、Scoutはソフト削除されたモデルを検索インデックスから削除しません。代わりに、インデックス付きレコードに非表示の__soft_deleted
属性を設定します。その後、withTrashed
またはonlyTrashed
メソッドを使用して、検索時にソフト削除されたレコードを取得できます。
use App\Models\Order; // Include trashed records when retrieving results...$orders = Order::search('Star Trek')->withTrashed()->get(); // Only include trashed records when retrieving results...$orders = Order::search('Star Trek')->onlyTrashed()->get();
forceDelete
を使用してソフト削除されたモデルが完全に削除されると、Scoutは自動的に検索インデックスから削除します。
エンジン検索のカスタマイズ
エンジンの検索動作を高度にカスタマイズする必要がある場合は、search
メソッドの2番目の引数としてクロージャを渡すことができます。たとえば、このコールバックを使用して、検索クエリが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句を使用してください。
カスタムエンジン
エンジンの記述
組み込みのScout検索エンジンのいずれもニーズに合わない場合は、独自のエンジンを作成し、Scoutに登録できます。あなたのエンジンはLaravel\Scout\Engines\Engine
抽象クラスを拡張する必要があります。この抽象クラスには、カスタムエンジンが実装する必要がある8つのメソッドが含まれています。
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サービスコンテナから解決できます。App\Providers\AppServiceProvider
クラスまたはアプリケーションで使用される他のサービスプロバイダーのboot
メソッドからextend
メソッドを呼び出す必要があります。
use App\ScoutExtensions\MySqlSearchEngine;use Laravel\Scout\EngineManager; /** * Bootstrap any application services. */public function boot(): void{ resolve(EngineManager::class)->extend('mysql', function () { return new MySqlSearchEngine; });}
エンジンが登録された後、アプリケーションのconfig/scout.php
構成ファイルで、それをデフォルトのScoutdriver
として指定できます。
'driver' => 'mysql',