こんにちは、エリカです。
今回は、Laravelで全文検索を実装するアプローチについてです。全文検索といえば、とにかく情報量が多そうな Elasticsearch が候補のひとつになるかと思います。
それでは、Laravel から Elasticsearch をどのように扱えばいいのでしょうか。
Laravelの公式パッケージに、Laravel Scout があります。
Laravel Scout(スカウト、斥候)は、Eloquentモデルへ、シンプルなドライバベースのフルテキストサーチを提供します。モデルオブサーバを使い、Scoutは検索インデックスを自動的にEloquentレコードと同期します。
現在、ScoutはAlgoliaドライバを用意しています。カスタムドライバは簡単に書けますので、独自の検索を実装し、Scoutを拡張できます。
この Laravel Scout を利用して、Elasticsearch を利用するところまでを試してみます。
Elasticsearchの準備
まずは、手元で、 Elasticsearch を動かしておきます。Laradockなら elasticsearch
コンテナを起動するだけです。簡単ですね。
docker-compose up -d elasticsearch
Laravelに必要パッケージのインストール
次に、 Laravelに必要なパッケージをインストールしていきます。
composer require laravel/scout
composer require elasticsearch/elasticsearch
laravel/scout
がドライバベースの検索エンジンです。デフォルトのドライバとして algolia
が用意されているのみですので、これを elasticsearch
を利用するドライバに置き換えていきます。
設定ファイルの準備
検索用の設定ファイルを準備します。artisan
コマンドを使えば、自動で作成できます。
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
そうして作成された config/scout.php
に下記のようにインデックス名やホスト名を追加しておきます。
'elasticsearch' => [
'index' => env('ELASTICSEARCH_INDEX', 'scout'),
'hosts' => [
env('ELASTICSEARCH_HOST', 'http://localhost'),
],
],
.env
ファイルで、 ELASTICSEARCH_HOST
を指定します。また、検索エンジンも elasticsearch
を利用するように指定します。
SCOUT_DRIVER=elasticsearch
ELASTICSEARCH_HOST=http://elasticsearch
ただ、この時点では、 elasticsearch
という検索ドライバは存在していませんので、それを作成します。
Elasticsearchを扱うLaravel Scoutドライバの作成
それでは、 Elasticsearch
を扱う検索ドライバを Scout
に追加します。
まずは、 app/Scout/ElasticsearchEngine.php
を作成します。
<?php
namespace App\Scout;
use Elasticsearch\Client as Elastic;
use Laravel\Scout\Builder;
use Laravel\Scout\Engines\Engine;
class ElasticsearchEngine extends Engine
{
protected $elastic;
protected $index;
public function __construct(Elastic $elastic, $index)
{
$this->elastic = $elastic;
$this->index = $index;
}
public function update($models)
{
// TODO: Implement update() method.
}
public function delete($models)
{
// TODO: Implement delete() method.
}
public function search(Builder $builder)
{
// TODO: Implement search() method.
}
public function paginate(Builder $builder, $perPage, $page)
{
// TODO: Implement paginate() method.
}
public function mapIds($results)
{
// TODO: Implement mapIds() method.
}
public function map(Builder $builder, $results, $model)
{
// TODO: Implement map() method.
}
public function getTotalCount($results)
{
// TODO: Implement getTotalCount() method.
}
public function flush($model)
{
// TODO: Implement flush() method.
}
}
作成したドライバの登録
次に、ElasticsearchServiceProvider.php
を用意し、先ほど作成した、 Elasticsearch
エンジンを elasticsearch
という検索ドライバ名で利用できるようにします。
<?php
namespace App\Providers;
use App\Scout\ElasticsearchEngine;
use Elasticsearch\ClientBuilder;
use Illuminate\Support\ServiceProvider;
use Laravel\Scout\EngineManager;
class ElasticsearchServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
resolve(EngineManager::class)->extend('elasticsearch', function ($app) {
return new ElasticsearchEngine(
ClientBuilder::fromConfig([
'hosts' => config('scout.elasticsearch.hosts'),
]),
config('scout.elasticsearch.index')
);
});
}
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}
}
EloquentとLaravel Scoutの同期
EloquentにSearchableトレイトを指定すると、Eloquentの各種イベントで検索エンジンドライバのメソッドが自動的に呼び出されるようになります。
class Post extends Model
{
use Searchable;
}
たとえば、Post::create()
などの更新処理が行われた場合は、 ElasticsearchEngine::update()
が呼び出されます。
あとは、ElasticsearchEngine
の各メソッドでどのようなデータのやりとりを行なっていくかの記述をしていけばいいだけです。
まとめ
Elasticsearchとの連携もLaravelなら簡単ですね。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。