Laravel Scout¶
はじめに¶
Laravel Scout は、Eloquentモデルにフルテキスト検索を追加するためのシンプルでドライバベースのソリューションを提供します。モデルオブザーバーを使用して、ScoutはEloquentレコードと検索インデックスを自動的に同期します。
現在、Scoutは Algolia、Meilisearch、Typesense、およびMySQL / PostgreSQL (database
) ドライバとともに提供されています。さらに、Scoutにはローカル開発用に設計された「コレクション」ドライバが含まれており、外部依存関係やサードパーティサービスを必要としません。また、カスタムドライバの作成は簡単であり、独自の検索実装でScoutを拡張することができます。
インストール¶
まず、Composerパッケージマネージャを介してScoutをインストールします:
Scoutをインストールした後、vendor:publish
Artisanコマンドを使用してScoutの設定ファイルを公開する必要があります。このコマンドは、scout.php
設定ファイルをアプリケーションのconfig
ディレクトリに公開します:
最後に、検索可能にしたいモデルに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もインストールする必要があります:
Meilisearch¶
Meilisearch は、非常に高速でオープンソースの検索エンジンです。ローカルマシンにMeilisearchをインストールする方法がわからない場合は、Laravelの公式サポートされているDocker開発環境であるLaravel Sailを使用できます。
Meilisearchドライバを使用する場合、Composerパッケージマネージャを介してMeilisearch PHP SDKをインストールする必要があります:
次に、SCOUT_DRIVER
環境変数とMeilisearchのhost
およびkey
認証情報をアプリケーションの.env
ファイル内に設定します:
Meilisearchに関する詳細情報については、Meilisearchのドキュメントを参照してください。
さらに、meilisearch/meilisearch-php
のバージョンがMeilisearchバイナリバージョンと互換性があることを確認する必要があります。互換性については、Meilisearchのバイナリ互換性に関するドキュメントを確認してください。
Warning
Meilisearchを使用するアプリケーションでScoutをアップグレードする場合、常にMeilisearchサービス自体の追加の破壊的変更を確認する必要があります。
Typesense¶
Typesense は、非常に高速でオープンソースの検索エンジンであり、キーワード検索、セマンティック検索、地理検索、ベクトル検索をサポートしています。
Typesenseは自己ホストすることも、Typesense Cloudを使用することもできます。
ScoutでTypesenseを使い始めるには、Composerパッケージマネージャを介してTypesense PHP SDKをインストールします:
次に、SCOUT_DRIVER
環境変数とTypesenseのホストおよびAPIキー認証情報をアプリケーションの.env
ファイル内に設定します:
Laravel Sailを使用している場合、TYPESENSE_HOST
環境変数をDockerコンテナ名に合わせて調整する必要があるかもしれません。また、インストールのポート、パス、プロトコルをオプションで指定することもできます:
Typesenseコレクションの追加設定とスキーマ定義は、アプリケーションのconfig/scout.php
設定ファイル内にあります。Typesenseに関する詳細情報については、Typesenseのドキュメントを参照してください。
Typesenseへのデータ保存の準備¶
Typesenseを使用する場合、検索可能なモデルは、モデルの主キーを文字列にキャストし、作成日をUNIXタイムスタンプにキャストするtoSearchableArray
メソッドを定義する必要があります:
/**
* モデルのインデックス可能なデータ配列を取得します。
*
* @return array<string, mixed>
*/
public function toSearchableArray()
{
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
を実行して、既存のインデックス化されたデータをすべて削除し、スキーマを再作成するか、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;
/**
* モデルに関連付けられたインデックスの名前を取得します。
*/
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,
];
}
フィルタ可能なデータとインデックス設定の設定 (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'],
// その他の設定フィールド...
],
Flight::class => [
'filterableAttributes'=> ['id', 'destination'],
'sortableAttributes' => ['updated_at'],
],
],
],
特定のインデックスの基になるモデルがソフトデリート可能であり、index-settings
配列に含まれている場合、Scoutは自動的にそのインデックスでソフトデリートされたモデルのフィルタリングをサポートします。ソフトデリート可能なモデルインデックスに他のフィルタ可能またはソート可能な属性を定義する必要がない場合、そのモデルのindex-settings
配列に空のエントリを追加するだけで済みます。
アプリケーションのインデックス設定を構成した後、scout:sync-index-settings
Artisanコマンドを実行する必要があります。このコマンドは、現在構成されているインデックス設定をMeilisearchに通知します。便宜上、このコマンドをデプロイプロセスの一部にすることをお勧めします。
モデル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のダッシュボード内で検索分析を表示する際に役立つ場合があります。ユーザー識別を有効にするには、アプリケーションの.env
ファイルでSCOUT_IDENTIFY
環境変数をtrue
として定義します。
この機能を有効にすると、リクエストのIPアドレスと認証されたユーザーの主識別子がAlgoliaに渡され、ユーザーが行ったすべての検索リクエストに関連付けられます。
データベース / コレクションエンジン¶
データベースエンジン¶
Warning
データベースエンジンは現在、MySQLとPostgreSQLをサポートしています。
アプリケーションが中小規模のデータベースと対話している場合や、軽いワークロードを持っている場合、Scoutの「データベース」エンジンを使用して始める方が便利かもしれません。データベースエンジンは、既存のデータベースから結果をフィルタリングする際に「where like」句と全文インデックスを使用して、クエリに適用される検索結果を決定します。
データベースエンジンを使用するには、SCOUT_DRIVER
環境変数の値をdatabase
に設定するか、アプリケーションのscout
設定ファイルでdatabase
ドライバを直接指定します。
データベースエンジンを好みのドライバとして指定したら、検索可能なデータの設定を行う必要があります。その後、モデルに対して検索クエリの実行を開始できます。Algolia、Meilisearch、Typesenseインデックスのシードに必要なインデックス作成などの検索エンジンインデックス作成は、データベースエンジンを使用する場合は不要です。
データベース検索戦略のカスタマイズ¶
デフォルトでは、データベースエンジンは、検索可能なデータとして設定されたすべてのモデル属性に対して「where like」クエリを実行します。ただし、状況によっては、これによりパフォーマンスが低下する可能性があります。したがって、データベースエンジンの検索戦略を設定して、特定の列が全文検索クエリを使用したり、文字列のプレフィックス(example%
)のみを検索する「where like」制約を使用したり、文字列全体(%example%
)を検索する代わりに使用するように設定できます。
この動作を定義するには、モデルのtoSearchableArray
メソッドにPHP属性を割り当てることができます。追加の検索戦略動作が割り当てられていない列は、デフォルトの「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,
];
}
Warning
列に全文クエリ制約を指定する前に、その列が全文インデックスに割り当てられていることを確認してください。
コレクションエンジン¶
ローカル開発中にAlgolia、Meilisearch、Typesense検索エンジンを自由に使用できますが、「コレクション」エンジンを使用して始める方が便利かもしれません。コレクションエンジンは、既存のデータベースからの結果に対して「where」句とコレクションフィルタリングを使用して、クエリに適用される検索結果を決定します。このエンジンを使用する場合、検索可能なモデルを「インデックス」する必要はありません。ローカルデータベースから単純に取得されます。
コレクションエンジンを使用するには、SCOUT_DRIVER
環境変数の値をcollection
に設定するか、アプリケーションのscout
設定ファイルでcollection
ドライバを直接指定します。
コレクションドライバを優先ドライバとして指定したら、モデルに対して検索クエリを実行できます。Algolia、Meilisearch、Typesenseインデックスのシードに必要なインデックス作成など、検索エンジンのインデックス作成は、コレクションエンジンを使用する場合は不要です。
データベースエンジンとの違い¶
一見すると、「データベース」と「コレクション」エンジンは非常によく似ています。どちらもデータベースと直接やり取りして検索結果を取得します。しかし、コレクションエンジンはフルテキストインデックスやLIKE
句を使用して一致するレコードを見つけることはありません。代わりに、可能なすべてのレコードを取得し、LaravelのStr::is
ヘルパーを使用して、検索文字列がモデル属性値内に存在するかどうかを判断します。
コレクションエンジンは、Laravelがサポートするすべてのリレーショナルデータベース(SQLiteやSQL Serverを含む)で動作するため、最も移植性の高い検索エンジンです。ただし、Scoutのデータベースエンジンよりも効率は低くなります。
インデックス作成¶
バッチインポート¶
既存のプロジェクトにScoutをインストールする場合、既にデータベースにレコードが存在する可能性があります。Scoutは、既存のレコードを検索インデックスにインポートするために使用できるscout:import
Artisanコマンドを提供しています。
flush
コマンドを使用して、モデルのすべてのレコードを検索インデックスから削除できます。
インポートクエリの変更¶
バッチインポートに使用されるクエリを変更したい場合は、モデルにmakeAllSearchableUsing
メソッドを定義できます。これは、モデルをインポートする前に必要な関係の読み込みを追加するのに最適な場所です。
use Illuminate\Database\Eloquent\Builder;
/**
* モデルを検索可能にする際に使用されるクエリを変更する。
*/
protected function makeAllSearchableUsing(Builder $query): Builder
{
return $query->with('author');
}
Warning
makeAllSearchableUsing
メソッドは、モデルをバッチインポートするためにキューを使用する場合には適用されない可能性があります。ジョブによって処理されるモデルコレクションの場合、関係は復元されません。
レコードの追加¶
Laravel\Scout\Searchable
トレイトをモデルに追加したら、モデルインスタンスをsave
またはcreate
するだけで、自動的に検索インデックスに追加されます。キューを使用するようにScoutを設定している場合、この操作はキューワーカーによってバックグラウンドで実行されます。
クエリによるレコードの追加¶
Eloquentクエリを介してモデルのコレクションを検索インデックスに追加したい場合は、Eloquentクエリにsearchable
メソッドをチェーンできます。searchable
メソッドはクエリの結果をチャンク分割し、レコードを検索インデックスに追加します。ここでも、Scoutをキューを使用するように設定している場合、すべてのチャンクはキューワーカーによってバックグラウンドでインポートされます。
Eloquentリレーションインスタンスにsearchable
メソッドを呼び出すこともできます。
または、メモリ内に既にEloquentモデルのコレクションがある場合は、コレクションインスタンスにsearchable
メソッドを呼び出して、モデルインスタンスを対応するインデックスに追加できます。
Note
searchable
メソッドは「upsert」操作と考えることができます。つまり、モデルレコードが既にインデックスに存在する場合は更新されます。インデックスに存在しない場合は、インデックスに追加されます。
レコードの更新¶
検索可能なモデルを更新するには、モデルインスタンスのプロパティを更新し、データベースにsave
するだけです。Scoutは自動的に変更を検索インデックスに保持します。
Eloquentクエリインスタンスにsearchable
メソッドを呼び出して、モデルのコレクションを更新することもできます。モデルが検索インデックスに存在しない場合は、作成されます。
リレーション内のすべてのモデルの検索インデックスレコードを更新したい場合は、リレーションインスタンスにsearchable
を呼び出すことができます。
または、メモリ内に既にEloquentモデルのコレクションがある場合は、コレクションインスタンスにsearchable
メソッドを呼び出して、モデルインスタンスを対応するインデックスで更新できます。
インポート前のレコードの変更¶
検索可能にする前にモデルのコレクションを準備する必要がある場合があります。たとえば、関係を事前に読み込んで、関係データを効率的に検索インデックスに追加したい場合です。これを実現するには、対応するモデルにmakeSearchableUsing
メソッドを定義します。
use Illuminate\Database\Eloquent\Collection;
/**
* 検索可能にするモデルのコレクションを変更する。
*/
public function makeSearchableUsing(Collection $models): Collection
{
return $models->load('author');
}
レコードの削除¶
インデックスからレコードを削除するには、データベースからモデルを単にdelete
するだけです。これは、ソフトデリートモデルを使用している場合でも可能です。
レコードを削除する前にモデルを取得したくない場合は、Eloquentクエリインスタンスにunsearchable
メソッドを使用できます。
リレーション内のすべてのモデルの検索インデックスレコードを削除したい場合は、リレーションインスタンスにunsearchable
を呼び出すことができます。
または、メモリ内に既にEloquentモデルのコレクションがある場合は、コレクションインスタンスにunsearchable
メソッドを呼び出して、モデルインスタンスを対応するインデックスから削除できます。
モデルレコードを対応するインデックスからすべて削除するには、removeAllFromSearch
メソッドを呼び出すことができます。
インデックス作成の一時停止¶
モデルデータを検索インデックスに同期せずに、モデルに対してEloquent操作のバッチを実行する必要がある場合があります。withoutSyncingToSearch
メソッドを使用してこれを行うことができます。このメソッドは、すぐに実行される単一のクロージャを受け取ります。クロージャ内で発生するモデル操作は、モデルのインデックスに同期されません。
条件付き検索可能なモデルインスタンス¶
特定の条件でのみモデルを検索可能にする必要がある場合があります。たとえば、App\Models\Post
モデルが「下書き」と「公開済み」の2つの状態のいずれかになるとします。「公開済み」の投稿のみを検索可能にする場合があります。これを実現するには、モデルにshouldBeSearchable
メソッドを定義します。
/**
* モデルが検索可能であるべきかどうかを判断する。
*/
public function shouldBeSearchable(): bool
{
return $this->isPublished();
}
shouldBeSearchable
メソッドは、save
およびcreate
メソッド、クエリ、またはリレーションを介してモデルを操作する場合にのみ適用されます。searchable
メソッドを使用してモデルまたはコレクションを直接検索可能にすると、shouldBeSearchable
メソッドの結果が上書きされます。
Warning
shouldBeSearchable
メソッドは、Scoutの「データベース」エンジンを使用する場合には適用されません。検索可能なデータは常にデータベースに保存されるためです。データベースエンジンを使用する場合に同様の動作を実現するには、代わりにwhere句を使用する必要があります。
検索¶
モデルの検索を開始するには、search
メソッドを使用します。検索メソッドは、モデルを検索するために使用される単一の文字列を受け取ります。その後、検索クエリにget
メソッドをチェーンして、指定された検索クエリに一致するEloquentモデルを取得する必要があります。
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
メソッドを使用できます。
カスタムインデックス¶
検索クエリは通常、モデルのsearchableAs
メソッドで指定されたインデックスで実行されます。ただし、代わりに検索するカスタムインデックスを指定するには、within
メソッドを使用できます。
Where句¶
Scoutを使用すると、検索クエリに単純な「where」句を追加できます。現在、これらの句は基本的な数値の等価性チェックのみをサポートしており、主に所有者IDによる検索クエリのスコープに役立ちます。検索インデックスはリレーショナルデータベースではないため、より高度な「where」句は現在サポートされていません。
whereIn
メソッドを使用して、結果を特定の値のセットに制限できます。
Scoutのwhere句は、Algoliaのような検索エンジンでのみ機能します。Scoutの「コレクション」エンジンを使用する場合、where
メソッドは無視されます。
Scoutでは、検索クエリにシンプルな「where」句を追加できます。現在、これらの句は基本的な数値の等価チェックのみをサポートしており、主に所有者IDによる検索クエリのスコープ指定に役立ちます。
さらに、whereIn
メソッドを使用して、指定された列の値が指定された配列内に含まれていることを確認できます。
whereNotIn
メソッドは、指定された列の値が指定された配列内に含まれていないことを確認します。
検索インデックスはリレーショナルデータベースではないため、より高度な「where」句は現在サポートされていません。
Warning
アプリケーションがMeilisearchを使用している場合、Scoutの「where」句を利用する前に、アプリケーションのフィルタ可能な属性を設定する必要があります。
ページネーション¶
モデルのコレクションを取得するだけでなく、paginate
メソッドを使用して検索結果をページネーションすることもできます。このメソッドは、従来のEloquentクエリをページネーションした場合と同様に、Illuminate\Pagination\LengthAwarePaginator
インスタンスを返します。
paginate
メソッドの最初の引数として、ページごとに取得するモデルの数を指定できます。
結果を取得したら、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);
});
Warning
検索エンジンはEloquentモデルのグローバルスコープ定義を認識しないため、Scoutのページネーションを利用するアプリケーションでグローバルスコープを使用しないでください。または、Scoutで検索する際にグローバルスコープの制約を再現する必要があります。
ソフトデリート¶
インデックス付けされたモデルがソフトデリートされており、ソフトデリートされたモデルを検索する必要がある場合は、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();
Note
ソフトデリートされたモデルが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;
/**
* 任意のアプリケーションサービスのブートストラップ
*/
public function boot(): void
{
resolve(EngineManager::class)->extend('mysql', function () {
return new MySqlSearchEngine;
});
}
エンジンを登録したら、アプリケーションのconfig/scout.php
設定ファイルでデフォルトのScoutdriver
として指定できます。