はじめに

Laravel Scout は、Eloquent モデル にフルテキスト検索を追加するためのシンプルでドライバベースのソリューションを提供します。モデルオブザーバーを使用することで、Scout は自動的に検索インデックスを Eloquent レコードと同期させます。

現在、Scout には AlgoliaMeilisearchTypesense、および MySQL / PostgreSQL (database) ドライバが付属しています。さらに、Scout にはローカル開発用に設計された「コレクション」ドライバが含まれており、外部依存関係やサードパーティサービスを必要としません。さらに、カスタムドライバの作成は簡単で、独自の検索実装で Scout を拡張することができます。

インストール

まず、Composer パッケージマネージャーを使用して Scout をインストールします:

  1. composer require laravel/scout

Scout をインストールした後、vendor:publish Artisan コマンドを使用して Scout 設定ファイルを公開する必要があります。このコマンドは、scout.php 設定ファイルをアプリケーションの config ディレクトリに公開します:

  1. php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

最後に、検索可能にしたいモデルに Laravel\Scout\Searchable トレイトを追加します。このトレイトは、モデルオブザーバーを登録し、モデルを検索ドライバと自動的に同期させます:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Laravel\Scout\Searchable;
  5. class Post extends Model
  6. {
  7. use Searchable;
  8. }

キュー処理

Scout を使用するために厳密には必要ありませんが、ライブラリを使用する前に キュードライバ を設定することを強くお勧めします。キューワーカーを実行すると、Scout はモデル情報を検索インデックスに同期するすべての操作をキューに入れることができ、アプリケーションの Web インターフェースの応答時間が大幅に改善されます。

キュードライバを設定したら、queue 設定ファイルの config/scout.php オプションの値を true に設定します:

  1. 'queue' => true,

queue オプションが false に設定されている場合でも、Algolia や Meilisearch のような一部の Scout ドライバは常にレコードを非同期でインデックス化することを忘れないでください。つまり、Laravel アプリケーション内でインデックス操作が完了しても、検索エンジン自体が新しいおよび更新されたレコードをすぐに反映しない場合があります。

Scout ジョブが利用する接続とキューを指定するには、queue 設定オプションを配列として定義できます:

  1. 'queue' => [
  2. 'connection' => 'redis',
  3. 'queue' => 'scout'
  4. ],

もちろん、Scout ジョブが利用する接続とキューをカスタマイズする場合は、その接続とキューでジョブを処理するためにキューワーカーを実行する必要があります:

  1. php artisan queue:work redis --queue=scout

ドライバの前提条件

Algolia

Algolia ドライバを使用する場合は、id および secret の資格情報を config/scout.php 設定ファイルに設定する必要があります。資格情報が設定されたら、Composer パッケージマネージャーを介して Algolia PHP SDK をインストールする必要があります:

  1. composer require algolia/algoliasearch-client-php

Meilisearch

Meilisearch は、非常に高速でオープンソースの検索エンジンです。ローカルマシンに Meilisearch をインストールする方法がわからない場合は、Laravel の公式にサポートされている Docker 開発環境である Laravel Sail を使用できます。

Meilisearch ドライバを使用する場合は、Composer パッケージマネージャーを介して Meilisearch PHP SDK をインストールする必要があります:

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

次に、SCOUT_DRIVER 環境変数とアプリケーションの .env ファイル内に Meilisearch host および key の資格情報を設定します:

  1. SCOUT_DRIVER=meilisearch
  2. MEILISEARCH_HOST=http://127.0.0.1:7700
  3. MEILISEARCH_KEY=masterKey

Meilisearch に関する詳細情報は、Meilisearch ドキュメント を参照してください。

さらに、Meilisearch のバイナリ互換性に関するドキュメント を確認して、Meilisearch バイナリバージョンと互換性のある meilisearch/meilisearch-php のバージョンをインストールしていることを確認してください。

Meilisearch を利用するアプリケーションで Scout をアップグレードする際は、常に Meilisearch サービス自体の追加の破壊的変更を確認してください

Typesense

Typesense は、超高速のオープンソース検索エンジンで、キーワード検索、セマンティック検索、地理検索、ベクトル検索をサポートしています。

Typesense を セルフホスト するか、Typesense Cloud を使用できます。

Scout と一緒に Typesense を使用するには、Composer パッケージマネージャーを介して Typesense PHP SDK をインストールします:

  1. composer require typesense/typesense-php

次に、SCOUT_DRIVER 環境変数とアプリケーションの .env ファイル内に Typesense ホストおよび API キーの資格情報を設定します:

  1. SCOUT_DRIVER=typesense
  2. TYPESENSE_API_KEY=masterKey
  3. TYPESENSE_HOST=localhost

Laravel Sail を使用している場合は、Docker コンテナ名に合わせて TYPESENSE_HOST 環境変数を調整する必要があるかもしれません。また、インストールのポート、パス、プロトコルを指定することもできます:

  1. TYPESENSE_PORT=8108
  2. TYPESENSE_PATH=
  3. TYPESENSE_PROTOCOL=http

Typesense コレクションの追加設定やスキーマ定義は、アプリケーションの config/scout.php 設定ファイル内に見つけることができます。Typesense に関する詳細情報は、Typesense ドキュメント を参照してください。

Typesense におけるデータの保存準備

Typesense を利用する場合、検索可能なモデルは、モデルの主キーを文字列にキャストし、作成日を UNIX タイムスタンプに変換する toSearchableArray メソッドを定義する必要があります:

  1. /**
  2. * Get the indexable data array for the model.
  3. *
  4. * @return array<string, mixed>
  5. */
  6. public function toSearchableArray()
  7. {
  8. return array_merge($this->toArray(),[
  9. 'id' => (string) $this->id,
  10. 'created_at' => $this->created_at->timestamp,
  11. ]);
  12. }

また、アプリケーションの config/scout.php ファイル内に Typesense コレクションスキーマを定義する必要があります。コレクションスキーマは、Typesense を介して検索可能な各フィールドのデータ型を説明します。利用可能なすべてのスキーマオプションに関する詳細情報は、Typesense ドキュメント を参照してください。

Typesense コレクションのスキーマを定義した後に変更する必要がある場合は、scout:flushscout:import を実行して、すべての既存のインデックスデータを削除し、スキーマを再作成することができます。または、Typesense の API を使用して、インデックスデータを削除せずにコレクションのスキーマを変更することもできます。

検索可能なモデルがソフトデリート可能な場合は、アプリケーションの config/scout.php 設定ファイル内の対応する Typesense スキーマに soft_deleted フィールドを定義する必要があります:

  1. User::class => [
  2. 'collection-schema' => [
  3. 'fields' => [
  4. // ...
  5. [
  6. 'name' => '__soft_deleted',
  7. 'type' => 'int32',
  8. 'optional' => true,
  9. ],
  10. ],
  11. ],
  12. ],

動的検索パラメータ

Typesense を使用すると、options メソッドを介して検索操作を実行する際に、検索パラメータ を動的に変更できます:

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

設定

モデルインデックスの設定

各 Eloquent モデルは、特定の検索「インデックス」と同期されており、そのモデルのすべての検索可能なレコードが含まれています。言い換えれば、各インデックスは MySQL テーブルのように考えることができます。デフォルトでは、各モデルはモデルの典型的な「テーブル」名に一致するインデックスに永続化されます。通常、これはモデル名の複数形ですが、searchableAs メソッドをオーバーライドすることでモデルのインデックスをカスタマイズすることができます:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Laravel\Scout\Searchable;
  5. class Post extends Model
  6. {
  7. use Searchable;
  8. /**
  9. * Get the name of the index associated with the model.
  10. */
  11. public function searchableAs(): string
  12. {
  13. return 'posts_index';
  14. }
  15. }

検索可能なデータの設定

デフォルトでは、特定のモデルの toArray 形式全体がその検索インデックスに永続化されます。検索インデックスに同期されるデータをカスタマイズしたい場合は、モデルの toSearchableArray メソッドをオーバーライドできます:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Laravel\Scout\Searchable;
  5. class Post extends Model
  6. {
  7. use Searchable;
  8. /**
  9. * Get the indexable data array for the model.
  10. *
  11. * @return array<string, mixed>
  12. */
  13. public function toSearchableArray(): array
  14. {
  15. $array = $this->toArray();
  16. // Customize the data array...
  17. return $array;
  18. }
  19. }

Meilisearch のような一部の検索エンジンは、正しい型のデータに対してのみフィルター操作 (>< など) を実行します。したがって、これらの検索エンジンを使用して検索可能なデータをカスタマイズする場合は、数値が正しい型にキャストされていることを確認する必要があります:

  1. public function toSearchableArray()
  2. {
  3. return [
  4. 'id' => (int) $this->id,
  5. 'name' => $this->name,
  6. 'price' => (float) $this->price,
  7. ];
  8. }

フィルタブルデータとインデックス設定の設定 (Meilisearch)

Scout の他のドライバとは異なり、Meilisearch ではフィルタブル属性、ソート可能属性、その他のサポートされている設定フィールド などのインデックス検索設定を事前に定義する必要があります。

フィルタブル属性は、Scout の where メソッドを呼び出す際にフィルタリングする予定の属性であり、ソート可能属性は、Scout の orderBy メソッドを呼び出す際にソートする予定の属性です。インデックス設定を定義するには、アプリケーションの scout 設定ファイル内の meilisearch 設定エントリの index-settings 部分を調整します:

  1. use App\Models\User;
  2. use App\Models\Flight;
  3. 'meilisearch' => [
  4. 'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
  5. 'key' => env('MEILISEARCH_KEY', null),
  6. 'index-settings' => [
  7. User::class => [
  8. 'filterableAttributes'=> ['id', 'name', 'email'],
  9. 'sortableAttributes' => ['created_at'],
  10. // Other settings fields...
  11. ],
  12. Flight::class => [
  13. 'filterableAttributes'=> ['id', 'destination'],
  14. 'sortableAttributes' => ['updated_at'],
  15. ],
  16. ],
  17. ],

特定のインデックスの基になるモデルがソフトデリート可能で、index-settings 配列に含まれている場合、Scout はそのインデックスでソフトデリートモデルのフィルタリングを自動的にサポートします。ソフトデリートモデルインデックスに定義するフィルタブルまたはソート可能属性が他にない場合は、そのモデルの index-settings 配列に空のエントリを追加するだけで済みます:

  1. 'index-settings' => [
  2. Flight::class => []
  3. ],

アプリケーションのインデックス設定を構成した後、scout:sync-index-settings Artisan コマンドを呼び出す必要があります。このコマンドは、Meilisearch に現在設定されているインデックス設定を通知します。便利なことに、このコマンドをデプロイプロセスの一部にすることをお勧めします:

  1. php artisan scout:sync-index-settings

モデル ID の設定

デフォルトでは、Scout はモデルの主キーを検索インデックスに保存されるモデルの一意の ID / キーとして使用します。この動作をカスタマイズする必要がある場合は、モデルの getScoutKey および getScoutKeyName メソッドをオーバーライドできます:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Laravel\Scout\Searchable;
  5. class User extends Model
  6. {
  7. use Searchable;
  8. /**
  9. * Get the value used to index the model.
  10. */
  11. public function getScoutKey(): mixed
  12. {
  13. return $this->email;
  14. }
  15. /**
  16. * Get the key name used to index the model.
  17. */
  18. public function getScoutKeyName(): mixed
  19. {
  20. return 'email';
  21. }
  22. }

モデルごとの検索エンジンの設定

検索時、Scout は通常、アプリケーションの scout 設定ファイルに指定されたデフォルトの検索エンジンを使用します。ただし、特定のモデルの検索エンジンは、モデルの searchableUsing メソッドをオーバーライドすることで変更できます:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Laravel\Scout\Engines\Engine;
  5. use Laravel\Scout\EngineManager;
  6. use Laravel\Scout\Searchable;
  7. class User extends Model
  8. {
  9. use Searchable;
  10. /**
  11. * Get the engine used to index the model.
  12. */
  13. public function searchableUsing(): Engine
  14. {
  15. return app(EngineManager::class)->engine('meilisearch');
  16. }
  17. }

ユーザーの識別

Scout は、Algolia を使用する際にユーザーを自動的に識別することもできます。認証されたユーザーを検索操作に関連付けることは、Algolia のダッシュボード内で検索分析を表示する際に役立ちます。ユーザー識別を有効にするには、アプリケーションの .env ファイル内で SCOUT_IDENTIFY 環境変数を true として定義します:

  1. SCOUT_IDENTIFY=true

この機能を有効にすると、リクエストの IP アドレスと認証されたユーザーの主識別子が Algolia に渡され、このデータはユーザーによって行われた検索リクエストに関連付けられます。

データベース / コレクションエンジン

データベースエンジン

データベースエンジンは現在 MySQL と PostgreSQL をサポートしています。

アプリケーションが小規模から中規模のデータベースと対話する場合や軽い負荷がある場合、Scout の「データベース」エンジンを使用する方が便利かもしれません。データベースエンジンは、既存のデータベースからの結果をフィルタリングする際に「where like」句とフルテキストインデックスを使用して、クエリに適用可能な検索結果を決定します。

データベースエンジンを使用するには、SCOUT_DRIVER 環境変数の値を database に設定するか、アプリケーションの scout 設定ファイル内で database ドライバを直接指定します:

  1. SCOUT_DRIVER=database

データベースエンジンを優先ドライバとして指定したら、検索可能なデータを構成する必要があります。その後、モデルに対して検索クエリを実行することができます。Algolia、Meilisearch、または Typesense インデックスをシードするために必要なインデックス作成は、データベースエンジンを使用する際には不要です。

データベース検索戦略のカスタマイズ

デフォルトでは、データベースエンジンは、検索可能として構成されたすべてのモデル属性に対して「where like」クエリを実行します。ただし、状況によっては、これがパフォーマンスの低下を引き起こす可能性があります。したがって、データベースエンジンの検索戦略を構成して、指定された列の一部がフルテキスト検索クエリを利用するか、文字列の接頭辞を検索するために「where like」制約のみを使用するように設定できます (example%)。

この動作を定義するには、モデルの toSearchableArray メソッドに PHP 属性を割り当てることができます。追加の検索戦略の動作が割り当てられていない列は、デフォルトの「where like」戦略を引き続き使用します:

  1. use Laravel\Scout\Attributes\SearchUsingFullText;
  2. use Laravel\Scout\Attributes\SearchUsingPrefix;
  3. /**
  4. * Get the indexable data array for the model.
  5. *
  6. * @return array<string, mixed>
  7. */
  8. #[SearchUsingPrefix(['id', 'email'])]
  9. #[SearchUsingFullText(['bio'])]
  10. public function toSearchableArray(): array
  11. {
  12. return [
  13. 'id' => $this->id,
  14. 'name' => $this->name,
  15. 'email' => $this->email,
  16. 'bio' => $this->bio,
  17. ];
  18. }

列がフルテキストクエリ制約を使用するように指定する前に、その列にフルテキストインデックスが割り当てられていることを確認してください。

コレクションエンジン

Algolia、Meilisearch、または Typesense 検索エンジンをローカル開発中に使用することは自由ですが、「コレクション」エンジンを使用する方が便利かもしれません。コレクションエンジンは、既存のデータベースからの結果に対して「where」句とコレクションフィルタリングを使用して、クエリに適用可能な検索結果を決定します。このエンジンを使用する場合、検索可能なモデルを「インデックス」する必要はなく、単にローカルデータベースから取得されます。

コレクションエンジンを使用するには、SCOUT_DRIVER 環境変数の値を collection に設定するか、アプリケーションの scout 設定ファイル内で collection ドライバを直接指定します:

  1. SCOUT_DRIVER=collection

コレクションドライバを優先ドライバとして指定したら、モデルに対して検索クエリを実行することができます。Algolia、Meilisearch、または Typesense インデックスをシードするために必要なインデックス作成は、コレクションエンジンを使用する際には不要です。

データベースエンジンとの違い

一見すると、「データベース」と「コレクション」エンジンは非常に似ています。どちらもデータベースと直接対話して検索結果を取得します。ただし、コレクションエンジンは、フルテキストインデックスや LIKE 句を使用して一致するレコードを見つけることはありません。代わりに、すべての可能なレコードを引き出し、Laravel の Str::is ヘルパーを使用して、検索文字列がモデル属性値内に存在するかどうかを判断します。

コレクションエンジンは、Laravel によってサポートされているすべてのリレーショナルデータベースで動作するため、最もポータブルな検索エンジンですが、Scout のデータベースエンジンよりも効率が劣ります。

インデックス作成

バッチインポート

Scout を既存のプロジェクトにインストールする場合、インデックスにインポートする必要があるデータベースレコードがすでに存在するかもしれません。Scout は、すべての既存のレコードを検索インデックスにインポートするために使用できる scout:import Artisan コマンドを提供します:

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

flush コマンドは、モデルのすべてのレコードを検索インデックスから削除するために使用できます:

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

インポートクエリの変更

バッチインポートのためにすべてのモデルを取得するために使用されるクエリを変更したい場合は、モデルに makeAllSearchableUsing メソッドを定義できます。これは、モデルをインポートする前に必要なイager リレーションシップの読み込みを追加するのに最適な場所です:

  1. use Illuminate\Database\Eloquent\Builder;
  2. /**
  3. * Modify the query used to retrieve models when making all of the models searchable.
  4. */
  5. protected function makeAllSearchableUsing(Builder $query): Builder
  6. {
  7. return $query->with('author');
  8. }

makeAllSearchableUsing メソッドは、モデルをバッチインポートするためにキューを使用する場合には適用できないかもしれません。モデルコレクションがジョブによって処理されるとき、リレーションシップは 復元されません

レコードの追加

モデルに Laravel\Scout\Searchable トレイトを追加したら、モデルインスタンスを save または create するだけで、自動的に検索インデックスに追加されます。Scout を キューを使用するように設定した場合、この操作はキューワーカーによってバックグラウンドで実行されます:

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

クエリを介してレコードを追加

Eloquent クエリを介してモデルのコレクションを検索インデックスに追加したい場合は、Eloquent クエリに searchable メソッドをチェーンできます。searchable メソッドは、クエリの結果を チャンク し、レコードを検索インデックスに追加します。再度、Scout をキューを使用するように設定した場合、すべてのチャンクはキューワーカーによってバックグラウンドでインポートされます:

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

Eloquent リレーションシップインスタンスで searchable メソッドを呼び出すこともできます:

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

または、すでにメモリ内に Eloquent モデルのコレクションがある場合は、コレクションインスタンスで searchable メソッドを呼び出して、モデルインスタンスを対応するインデックスに追加できます:

  1. $orders->searchable();

searchable メソッドは「アップサート」操作と見なすことができます。言い換えれば、モデルレコードがすでにインデックスに存在する場合は更新され、検索インデックスに存在しない場合はインデックスに追加されます。

レコードの更新

検索可能なモデルを更新するには、モデルインスタンスのプロパティを更新し、save モデルをデータベースに保存するだけです。Scout は自動的に変更を検索インデックスに永続化します:

  1. use App\Models\Order;
  2. $order = Order::find(1);
  3. // Update the order...
  4. $order->save();

Eloquent クエリインスタンスで searchable メソッドを呼び出して、モデルのコレクションを更新することもできます。モデルが検索インデックスに存在しない場合は作成されます:

  1. Order::where('price', '>', 100)->searchable();

リレーションシップ内のすべてのモデルの検索インデックスレコードを更新したい場合は、リレーションシップインスタンスで searchable を呼び出すことができます:

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

または、すでにメモリ内に Eloquent モデルのコレクションがある場合は、コレクションインスタンスで searchable メソッドを呼び出して、対応するインデックス内のモデルインスタンスを更新できます:

  1. $orders->searchable();

インポート前のレコードの変更

時には、検索可能にする前にモデルのコレクションを準備する必要があります。たとえば、リレーションシップをイager ロードして、リレーションシップデータを効率的に検索インデックスに追加したい場合があります。これを実現するには、対応するモデルに makeSearchableUsing メソッドを定義します:

  1. use Illuminate\Database\Eloquent\Collection;
  2. /**
  3. * Modify the collection of models being made searchable.
  4. */
  5. public function makeSearchableUsing(Collection $models): Collection
  6. {
  7. return $models->load('author');
  8. }

レコードの削除

インデックスからレコードを削除するには、単にモデルをデータベースから delete すればよいです。これは、ソフトデリート モデルを使用している場合でも行えます:

  1. use App\Models\Order;
  2. $order = Order::find(1);
  3. $order->delete();

レコードを削除する前にモデルを取得したくない場合は、Eloquent クエリインスタンスで unsearchable メソッドを使用できます:

  1. Order::where('price', '>', 100)->unsearchable();

リレーションシップ内のすべてのモデルの検索インデックスレコードを削除したい場合は、リレーションシップインスタンスで unsearchable を呼び出すことができます:

  1. $user->orders()->unsearchable();

または、すでにメモリ内に Eloquent モデルのコレクションがある場合は、コレクションインスタンスで unsearchable メソッドを呼び出して、対応するインデックスからモデルインスタンスを削除できます:

  1. $orders->unsearchable();

すべてのモデルレコードを対応するインデックスから削除するには、removeAllFromSearch メソッドを呼び出します:

  1. Order::removeAllFromSearch();

インデックス作成の一時停止

時には、モデルに対して一連の Eloquent 操作を実行し、モデルデータを検索インデックスに同期させない必要があります。これを行うには、withoutSyncingToSearch メソッドを使用します。このメソッドは、単一のクロージャを受け入れ、即座に実行されます。クロージャ内で発生するモデル操作は、モデルのインデックスに同期されません:

  1. use App\Models\Order;
  2. Order::withoutSyncingToSearch(function () {
  3. // Perform model actions...
  4. });

条件付き検索可能モデルインスタンス

時には、特定の条件下でのみモデルを検索可能にする必要があります。たとえば、App\Models\Post モデルが「ドラフト」と「公開」の 2 つの状態のいずれかにあるとします。「公開」された投稿のみを検索可能にしたい場合があります。これを実現するには、モデルに shouldBeSearchable メソッドを定義します:

  1. /**
  2. * Determine if the model should be searchable.
  3. */
  4. public function shouldBeSearchable(): bool
  5. {
  6. return $this->isPublished();
  7. }

shouldBeSearchable メソッドは、save および create メソッド、クエリ、またはリレーションシップを介してモデルを操作する際にのみ適用されます。searchable メソッドを使用してモデルやコレクションを直接検索可能にすると、shouldBeSearchable メソッドの結果が上書きされます。

Scout の「データベース」エンジンを使用している場合、shouldBeSearchable メソッドは適用されません。すべての検索可能なデータは常にデータベースに保存されます。データベースエンジンを使用して同様の動作を実現するには、where 句 を使用する必要があります。

検索

モデルを検索するには、search メソッドを使用します。検索メソッドは、モデルを検索するために使用される単一の文字列を受け入れます。その後、get メソッドを検索クエリにチェーンして、指定された検索クエリに一致する Eloquent モデルを取得します:

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

Scout の検索結果は Eloquent モデルのコレクションを返すため、ルートやコントローラから直接結果を返すこともでき、自動的に JSON に変換されます:

  1. use App\Models\Order;
  2. use Illuminate\Http\Request;
  3. Route::get('/search', function (Request $request) {
  4. return Order::search($request->search)->get();
  5. });

生の検索結果を Eloquent モデルに変換される前に取得したい場合は、raw メソッドを使用できます:

  1. $orders = Order::search('Star Trek')->raw();

カスタムインデックス

検索クエリは通常、モデルの searchableAs メソッドで指定されたインデックスで実行されます。ただし、within メソッドを使用して、代わりに検索すべきカスタムインデックスを指定できます:

  1. $orders = Order::search('Star Trek')
  2. ->within('tv_shows_popularity_desc')
  3. ->get();

where 句

Scout は、検索クエリにシンプルな「where」句を追加することを許可します。現在、これらの句は基本的な数値の等価チェックのみをサポートしており、主にオーナー ID によって検索クエリをスコープするのに便利です:

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

さらに、whereIn メソッドを使用して、指定された列の値が指定された配列に含まれているかどうかを確認できます:

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

whereNotIn メソッドは、指定された列の値が指定された配列に含まれていないことを確認します:

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

検索インデックスはリレーショナルデータベースではないため、より高度な「where」句は現在サポートされていません。

アプリケーションが Meilisearch を使用している場合、Scout の「where」句を利用する前に、アプリケーションの フィルタブル属性 を構成する必要があります。

ページネーション

モデルのコレクションを取得するだけでなく、paginate メソッドを使用して検索結果をページネートすることもできます。このメソッドは、従来の Eloquent クエリを ページネートした かのように Illuminate\Pagination\LengthAwarePaginator インスタンスを返します:

  1. use App\Models\Order;
  2. $orders = Order::search('Star Trek')->paginate();

paginate メソッドに最初の引数として取得するモデルの数を渡すことで、ページごとに取得するモデルの数を指定できます:

  1. $orders = Order::search('Star Trek')->paginate(15);

結果を取得したら、結果を表示し、ページリンクを Blade を使用してレンダリングできます。従来の Eloquent クエリをページネートしたかのように:

  1. <div class="container">
  2. @foreach ($orders as $order)
  3. {{ $order->price }}
  4. @endforeach
  5. </div>
  6. {{ $orders->links() }}

もちろん、ページネーション結果を JSON として取得したい場合は、ルートやコントローラから直接ページネータインスタンスを返すことができます:

  1. use App\Models\Order;
  2. use Illuminate\Http\Request;
  3. Route::get('/orders', function (Request $request) {
  4. return Order::search($request->input('query'))->paginate(15);
  5. });

検索エンジンは Eloquent モデルのグローバルスコープ定義を認識しないため、Scout ページネーションを利用するアプリケーションではグローバルスコープを利用しないでください。または、Scout を介して検索する際にグローバルスコープの制約を再作成する必要があります。

ソフトデリート

インデックスされたモデルが ソフトデリート されていて、ソフトデリートモデルを検索する必要がある場合は、soft_delete 設定ファイルの config/scout.php オプションを true に設定します:

  1. 'soft_delete' => true,

この設定オプションが true の場合、Scout はソフトデリートモデルを検索インデックスから削除しません。代わりに、インデックスされたレコードに隠し soft_deleted 属性を設定します。その後、withTrashed または onlyTrashed メソッドを使用して検索時にソフトデリートレコードを取得できます:

  1. use App\Models\Order;
  2. // Include trashed records when retrieving results...
  3. $orders = Order::search('Star Trek')->withTrashed()->get();
  4. // Only include trashed records when retrieving results...
  5. $orders = Order::search('Star Trek')->onlyTrashed()->get();

ソフトデリートモデルが forceDelete を使用して完全に削除されると、Scout は自動的にそれを検索インデックスから削除します。

エンジン検索のカスタマイズ

エンジンの検索動作を高度にカスタマイズする必要がある場合は、search メソッドの第 2 引数としてクロージャを渡すことができます。たとえば、このコールバックを使用して、検索クエリが Algolia に渡される前に検索オプションにジオロケーションデータを追加できます:

  1. use Algolia\AlgoliaSearch\SearchIndex;
  2. use App\Models\Order;
  3. Order::search(
  4. 'Star Trek',
  5. function (SearchIndex $algolia, string $query, array $options) {
  6. $options['body']['query']['bool']['filter']['geo_distance'] = [
  7. 'distance' => '1000km',
  8. 'location' => ['lat' => 36, 'lon' => 111],
  9. ];
  10. return $algolia->search($query, $options);
  11. }
  12. )->get();

Eloquent 結果クエリのカスタマイズ

Scout がアプリケーションの検索エンジンから一致する Eloquent モデルのリストを取得した後、Eloquent を使用して主キーによってすべての一致するモデルを取得します。このクエリをカスタマイズするには、query メソッドを呼び出します。query メソッドは、Eloquent クエリビルダーインスタンスを引数として受け取るクロージャを受け入れます:

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

このコールバックは、関連するモデルがすでにアプリケーションの検索エンジンから取得された後に呼び出されるため、query メソッドは「フィルタリング」結果に使用すべきではありません。代わりに、Scout の where 句 を使用する必要があります。

カスタムエンジン

エンジンの作成

組み込みの Scout 検索エンジンのいずれかがニーズに合わない場合は、独自のカスタムエンジンを作成し、Scout に登録できます。エンジンは Laravel\Scout\Engines\Engine 抽象クラスを拡張する必要があります。この抽象クラスには、カスタムエンジンが実装しなければならない 8 つのメソッドが含まれています:

  1. use Laravel\Scout\Builder;
  2. abstract public function update($models);
  3. abstract public function delete($models);
  4. abstract public function search(Builder $builder);
  5. abstract public function paginate(Builder $builder, $perPage, $page);
  6. abstract public function mapIds($results);
  7. abstract public function map(Builder $builder, $results, $model);
  8. abstract public function getTotalCount($results);
  9. abstract public function flush($model);

これらのメソッドの実装を Laravel\Scout\Engines\AlgoliaEngine クラスで確認すると役立ちます。このクラスは、独自のエンジンでこれらのメソッドを実装する方法を学ぶための良い出発点を提供します。

エンジンの登録

カスタムエンジンを作成したら、Scout エンジンマネージャーの extend メソッドを使用して Scout に登録できます。Scout のエンジンマネージャーは、Laravel サービスコンテナから解決できます。App\Providers\AppServiceProvider クラスの boot メソッドまたはアプリケーションで使用される他のサービスプロバイダーから extend メソッドを呼び出す必要があります:

  1. use App\ScoutExtensions\MySqlSearchEngine;
  2. use Laravel\Scout\EngineManager;
  3. /**
  4. * Bootstrap any application services.
  5. */
  6. public function boot(): void
  7. {
  8. resolve(EngineManager::class)->extend('mysql', function () {
  9. return new MySqlSearchEngine;
  10. });
  11. }

エンジンが登録されたら、アプリケーションの config/scout.php 設定ファイルでデフォルトの Scout driver として指定できます:

  1. 'driver' => 'mysql',