Laravelは今日、ウェブサービスを構築する開発者にとって非常に頼りになる存在です。
オープンソースソフトウェアであるLaravelには、すぐに使える機能が多数揃っており、堅牢で機能的なアプリケーションを構築できます。
そうした機能のひとつである、Laravel Scoutは、アプリケーションの検索インデックスを管理するライブラリです。非常に柔軟性があり、開発者は設定を細かく調整できる上、インデックスの保存先にAlgolia、Meilisearch、MySQL、Postgresドライバを選択できます。
この記事では、Laravel Scoutを詳細に解説し、Laravelアプリケーションにドライバ経由で全文検索機能を追加する方法をご説明します。後半では、模型列車の名前を保存するデモLaravelアプリケーションを作成し、Laravel Scoutを使用して検索機能を追加していきます。
前提条件
以下の条件を前提として解説していきます。
- コンピュータにPHPコンパイラがインストールされている(本記事ではPHP 8.1を使用)
- コンピュータにDockerエンジン、またはDocker Desktopがインストールされている
- Algoliaのクラウドアカウントを所有している(無料で作成可能)
LaravelプロジェクトにScoutをインストールする方法
Scoutを使用するには、まず検索機能を追加するLaravelアプリケーションを作成します。Laravel-Scout Bashスクリプトには、Dockerコンテナ内でLaravelアプリケーションを生成するコマンドが含まれています。Dockerを使用すれば、MySQLデータベースなどの追加ソフトウェアのインストールは不要です。
Laravel-scoutスクリプトはBashスクリプト言語を使用するため、実行にはLinux環境が必要です。Windowsを使用している場合は、Windows Subsystem for Linux(WSL)を構成してください。
WSLを使用している場合は、ターミナルで以下のコマンドを実行し、好みのLinuxディストリビューションを設定します。
wsl -s ubuntu
次に、コンピューター上のプロジェクト格納場所に移動します。Laravel-Scoutスクリプトは、ここにプロジェクトディレクトリを生成します。desktopディレクトリ内にプロジェクトディレクトリを作成する場合、以下のようになります。
cd /desktop
以下のコマンドで、Laravel-Scoutスクリプトを実行します。このスクリプトは、定形のコードを含む、Dockerアプリケーションの雛形を生成するものです。
curl -s https://laravel.build/laravel-scout-app | bash
実行後、cd laravel-scout-app
で、ディレクトリを変更します。次にプロジェクトフォルダー内でsail-up
コマンドを実行して、アプリケーション用のDockerコンテナを起動します。
注意)多くのLinuxディストリビューションでは、一時的に権限を上げるためにsudo
コマンドを介して、コマンドを実行する必要があります。
./vendor/bin/sail up
次のようなエラーが発生する場合があります。
これを解決するには、sail up
コマンド内でAPP_PORT
変数を使用してポートを指定します。
APP_PORT=3001 ./vendor/bin/sail up
次に、以下のコマンドを使って、PHPサーバー上のArtisanでアプリケーションを実行します。
php artisan serve
ウェブブラウザから実行中のアプリケーションに「http://127.0.0.1:8000」でアクセスすると、デフォルトルートで、Laravelのウェルカムページが表示されます。
アプリケーションにLaravel Scoutを追加する方法
ターミナルで次のコマンドを入力して、Composer PHPパッケージマネージャを有効にし、プロジェクトにLaravel Scoutを追加します。
composer require laravel/scout
次にvendor:publishコマンドを使用して、Scout構成ファイルを作成します。このコマンドは、アプリケーションのconfigディレクトリにscout.php
設定ファイルを作成するものです。
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
次に、SCOUT_QUEUE
ブール値を含むように、.envファイルを変更します。
SCOUT_QUEUE
値の設定により、Scoutは操作をキューに入れ、レスポンスタイムを向上できます。MeilisearchのようなScoutドライバは、SCOUT_QUEUE値がなければ、新しいレコードをすぐに反映できません。
SCOUT_QUEUE=true
また、Dockerコンテナ内でMySQLデータベースを使用するために、.envファイルのDB_HOST
変数にlocalhostを設定します。
DB_HOST=127.0.0.1
モデルをマークしてインデックスを構成する方法
Scoutでは、検索可能なデータモデルがデフォルトで無効になっています。そのため、Laravel\Scout\Searchable
トレイトを使用して、明示的にモデルを検索可能としてマークする必要があります。
まず、デモTrain
アプリケーションのデータモデルを作成し、検索可能としてマークします。
モデルの作成方法
Train
アプリケーションには、所有する模型列車の名前を保存します。
以下のArtisanコマンドを実行して、create_trains_table
マイグレーションを生成します。
php artisan make:migration create_trains_table
マイグレーションは、指定した名前と現在のタイムスタンプを組み合わせた形式のファイル名で生成されます。
database/migrations/ディレクトリ内のマイグレーションファイルを開きます。
title列を追加するには、17行目付近のid()
カラムの後に以下のコードを追加します。これによって、title列が追加されます。
$table->string('title');
次のコマンドを実行して、マイグレーションを適用しましょう。
php artisan migrate
データベースマイグレーションを実行したら、app/Models/ディレクトリにTrain.phpファイルを作成してください。
Laravel\Scout\Searchableトレイトを追加する方法
Train
モデルにLaravel\Scout\Searchable
トレイトを追加して、検索可能とマークします。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Train extends Model
{
use Searchable;
public $fillable = ['title'];
また、searchableAs
メソッドをオーバーライドして検索インデックスを設定します。Scoutのデフォルトの動作は、モデルのテーブル名と一致するようにモデルを永続化します。
Train.phpファイルの上のコードブロックに続けて、以下のコードを追加します。
/**
* Retrieve the index name for the model.
*
* @return string
*/
public function searchableAs()
{
return 'trains_index';
}
}
ScoutでAlgoliaを使用する方法
Laravel Scoutを使用した最初の全文検索には、Algoliaドライバを使用します。Algoliaは大量のデータを検索するためのSaaS(Software as a Service)プラットフォームです。Algoliaには検索インデックスを管理するウェブダッシュボードと、ソフトウェア開発キット(SDK)を介して好きなプログラミング言語から利用できる堅牢なAPIがあります。
Laravelアプリケーションでは、PHP用のAlgoliaクライアントパッケージを使用します。
Algoliaのセットアップ方法
まず、アプリケーション用にAlgoliaのPHP検索クライアントパッケージをインストールします。
次のコマンドを実行してください。
composer require algolia/algoliasearch-client-php
次に、.envファイルにAlgoliaのアプリケーションIDとシークレットAPIキーの認証情報を設定します。
ウェブブラウザからAlgoliaの管理画面にアクセスし、アプリケーションIDとシークレットAPIキーの認証情報を取得します。
左側のサイドバーの一番下にある「Settings(設定)」をクリックして、「Settings」ページに移動します。
「Team and Access(チームとアクセス権)」セクションで「API Keys(APIキー)」をクリックし、Algoliaアカウントのキーを表示します。
API Keysページで「Application ID(アプリケーションID)」と「Admin API Key(管理APIキー)」の値をメモしてください。この認証情報を使用して、LaravelアプリケーションとAlgolia間の接続を認証します。
コードエディターを使用して、.envファイルに以下のコードを追加します。プレースホルダは、メモした対応するAlgolia API認証情報で置き換えてください。
ALGOLIA_APP_ID=APPLICATION_ID
ALGOLIA_SECRET=ADMIN_API_KEY
また、SCOUT_DRIVER
変数を以下のコードに置き換え、値をmeilisearch
からalgolia
に変更してください。この値によりScoutがAlgoliaドライバを使用します。
SCOUT_DRIVER=algolia
アプリケーションコントローラの作成方法
app/Http/Controllers/ディレクトリのTrainSearchController.phpファイル内に、アプリケーションのコントローラを実装します。このコントローラは、Train
モデルの一覧を表示し、データを追加します。
TrainSearchController.phpファイルに以下のコードブロックを追加し、コントローラを構築します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Train;
class TrainSearchController extends Controller
{
/**
* Compile the content for a trains list view.
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
public function index(Request $request)
{
if($request->has('titlesearch')){
$trains = Train::search($request->titlesearch)
->paginate(6);
}else{
$trains = Train::paginate(6);
}
return view('Train-search',compact('trains'));
}
/**
* Create a new train entry.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function create(Request $request)
{
$this->validate($request,['title'=>'required']);
$trains = Train::create($request->all());
return back();
}
}
アプリケーションルートの作成方法
続いて、列車の一覧を取得し、またデータベースに列車を追加するルートを作成します。
routes/web.phpファイルを開き、既存のコードを以下のブロックで置き換えてください。
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TrainSearchController;
Route::get('/', function () {
return view('welcome');
});
Route::get('trains-lists', [TrainSearchController::class, 'index']) -> name ('trains-lists');
Route::post('create-item', [TrainSearchController::class, 'create']) -> name ('create-item');
このコードは、アプリケーションに2つのルートを定義します。/trains-lists
ルートのGET
リクエストは、保存されているすべての列車データを一覧表示し、/create-item
ルートのPOST
リクエストは、列車データを作成します。
アプリケーションビューの作成方法
resources/views/ディレクトリ内にTrain-search.blade.phpファイルを作成します。このファイルは、検索機能のユーザーインターフェースを表示します。
以下のコードブロックをTrain-search.blade.phpファイルに追加し、検索機能用の単一ページを作成しましょう。
<!DOCTYPE html>
<html>
<head>
<title>Laravel - Laravel Scout Algolia Search Example</title>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-bold">Laravel Full-Text Search Using Scout </h2><br/>
<form method="POST" action="{{ route('create-item') }}" autocomplete="off">
@if(count($errors))
<div class="alert alert-danger">
<strong>Whoops!</strong> There is an error with your input.
<br/>
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="row">
<div class="col-md-6">
<div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
<input type="text" id="title" name="title" class="form-control" placeholder="Enter Title" value="{{ old('title') }}">
<span class="text-danger">{{ $errors->first('title') }}</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Create New Train</button>
</div>
</div>
</div>
</form>
<div class="panel panel-primary">
<div class="panel-heading">Train Management</div>
<div class="panel-body">
<form method="GET" action="{{ route('trains-lists') }}">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="text" name="titlesearch" class="form-control" placeholder="Enter Title For Search" value="{{ old('titlesearch') }}">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<button class="btn btn-primary">Search</button>
</div>
</div>
</div>
</form>
<table class="table">
<thead>
<th>Id</th>
<th>Train Title</th>
<th>Creation Date</th>
<th>Updated Date</th>
</thead>
<tbody>
@if($trains->count())
@foreach($trains as $key => $item)
<tr>
<td>{{ ++$key }}</td>
<td>{{ $item->title }}</td>
<td>{{ $item->created_at }}</td>
<td>{{ $item->updated_at }}</td>
</tr>
@endforeach
@else
<tr>
<td colspan="4">No train data available</td>
</tr>
@endif
</tbody>
</table>
{{ $trains->links() }}
</div>
</div>
</div>
</body>
</html>
上のHTMLコードには、データベースに保存する前に列車のタイトルを入力するためのフィールドとボタンを含むフォーム要素が含まれています。また、データベース内の列車データのid、title(タイトル)、created_at(作成日時)、updated_at(更新日時)情報を表示するHTMLテーブルも書かれています。
Algolia検索の使用方法
ページを表示するには、ウェブブラウザからhttp://127.0.0.1:8000/trains-listsにアクセスします。
データベースは現在空の状態です。入力フィールドにデモ用の列車のタイトルを入力し、「Create New Train(新しい列車の作成)」をクリックして保存します。
検索機能を使用するには、保存されている列車タイトルの中からキーワードを「Enter Title For Search(検索用タイトルを入力)」入力フィールドに入力し、「Search(検索)」をクリックします。
以下のように、タイトルにキーワードを含む列車データのみが表示されます。
Laravel ScoutとMeilisearch
Meilisearchはスピード、パフォーマンス、開発者体験の向上に焦点を当てたオープンソースの検索エンジンです。Algoliaと複数の機能を共有し、同じアルゴリズム、データ構造、研究結果を使用していますが、プログラミング言語は異なります。
開発者は、オンプレミスまたはクラウドインフラ内でMeilisearchのインスタンスを作成し、自身でサーバーを運用できます。またインフラを管理せずに製品を使用できるよう、Algoliaと同様のベータ版クラウドオファリングもあります。
現在のデモ環境では、すでにDockerコンテナ内でMeilisearchのローカルインスタンスが動作しています。ここからLaravel Scout機能を拡張し、Meilisearchインスタンスを使用できます。
LaravelアプリケーションにMeilisearchを追加するには、プロジェクトのターミナルで以下のコマンドを実行します。
composer require meilisearch/meilisearch-php
次に、.envファイル内のMeilisearch変数を変更して構成します。
.envファイルのSCOUT_DRIVER
、MEILISEARCH_HOST
、MEILISEARCH_KEY
変数を以下で置き換えてください。
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=LockKey
SCOUT_DRIVER
キーはScoutが使用するドライバを指定し、MEILISEARCH_HOST
はMeilisearchインスタンスが動作するドメインを指定します。開発時には必要ありませんが、本番環境ではMEILISEARCH_KEY
を追加することを推奨します。
注意)Meilisearchを優先ドライバとして使用する際は、Algolia IDとシークレットをコメントアウトしてください。
.envの構成が完了したら、以下のArtisanコマンドを使用して、既存レコードのインデックスを作成してください。
php artisan scout:import "App\Models\Train"
Laravel Scoutとデータベースエンジン
Scoutのデータベースエンジンは、小規模なデータベースを使用するアプリケーションや、それほど処理負荷のかからないアプリケーションに適しています。現在、データベースエンジンはPostgreSQLとMySQLをサポートしています。
このエンジンは、既存のデータベースに対して「where-like」句と全文検索インデックスを使用して、最も関連性の高い検索結果を取得します。また、使用する際、レコードのインデックスは必要ありません。
データベースエンジンを使用するには、SCOUT_DRIVER
.env変数をdatabaseに設定します。
Laravelアプリケーションの.envファイルを開き、SCOUT_DRIVER
変数の値を変更します。
SCOUT_DRIVER = database
ドライバをdatabaseに変更すると、Scoutが全文検索にデータベースエンジンを使用するようになります。
Laravel Scoutとコレクションエンジン
Scoutにはデータベースエンジンに加え、コレクションエンジンもあります。このエンジンは、「where」句とコレクションフィルタリングを使用して、最も関連性の高い検索結果を抽出します。
データベースエンジンとは異なり、Laravelのサポートするすべてのリレーショナルデータベースに対応しています。
SCOUT_DRIVER
環境変数をcollection
に設定するか、Scout構成ファイルでコレクションドライバを指定することで使用可能です。
SCOUT_DRIVER = collection
Elasticsearch Explorer
Elasticsearchクエリの強みを生かしたExplorerは、Laravel Scout用の最新のElasticsearchドライバ。互換性のあるScoutドライバが提供され、大量のデータをリアルタイムで保存、検索、分析できます。Laravelを使用したElasticsearchは、ミリ秒単位で結果を返します。
LaravelアプリケーションでElasticsearch Explorerドライバを使用するには、Laravel-Scoutスクリプトが生成したdocker-compose.ymlファイルで構成する必要があります。Elasticsearch用の構成を追加し、コンテナを再起動します。
docker-compose.ymlファイルを開き、内容を以下で置き換えてください。
# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.1
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.1/app
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
- redis
- meilisearch
- mailhog
- selenium
- pgsql
- elasticsearch
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: "%"
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
elasticsearch:
image: 'elasticsearch:7.13.4'
environment:
- discovery.type=single-node
ports:
- '9200:9200'
- '9300:9300'
volumes:
- 'sailelasticsearch:/usr/share/elasticsearch/data'
networks:
- sail
kibana:
image: 'kibana:7.13.4'
environment:
- elasticsearch.hosts=http://elasticsearch:9200
ports:
- '5601:5601'
networks:
- sail
depends_on:
- elasticsearch
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
retries: 3
timeout: 5s
pgsql:
image: 'postgres:13'
ports:
- '${FORWARD_DB_PORT:-5432}:5432'
environment:
PGPASSWORD: '${DB_PASSWORD:-secret}'
POSTGRES_DB: '${DB_DATABASE}'
POSTGRES_USER: '${DB_USERNAME}'
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
volumes:
- 'sailpgsql:/var/lib/postgresql/data'
networks:
- sail
healthcheck:
test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"]
retries: 3
timeout: 5s
meilisearch:
image: 'getmeili/meilisearch:latest'
ports:
- '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
volumes:
- 'sail-meilisearch:/meili_data'
networks:
- sail
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"]
retries: 3
timeout: 5s
mailhog:
image: 'mailhog/mailhog:latest'
ports:
- '${FORWARD_MAILHOG_PORT:-1025}:1025'
- '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
selenium:
image: 'selenium/standalone-chrome'
extra_hosts:
- 'host.docker.internal:host-gateway'
volumes:
- '/dev/shm:/dev/shm'
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
sail-redis:
driver: local
sail-meilisearch:
driver: local
sailpgsql:
driver: local
sailelasticsearch:
driver: local
次に、以下のコマンドを実行して、docker-compose.ymlファイルに追加したElasticsearchイメージを取得します。
docker-compose up
それから以下のComposerコマンドを実行して、Explorerをプロジェクトにインストールします。
composer require jeroen-g/explorer
また、Explorerドライバの構成ファイルも作成する必要があります。
以下のArtisanコマンドを実行して、構成を保存するexplorer.configファイルを生成します。
php artisan vendor:publish --tag=explorer.config
生成された構成ファイルは/configディレクトリにあります。
config/explorer.phpファイルで、indexes
キーを使用してモデルを参照できます。
'indexes' => [
\App\Models\Train::class
],
.envファイル内のSCOUT_DRIVER
変数の値をelastic
に変更し、ScoutがExplorerドライバを使用するように構成します。
SCOUT_DRIVER = elastic
この時点で、Explorerインターフェースを実装し、 mappableAs()
メソッドをオーバーライドすることで、 Train
モデル内でExplorerを使用できます。
App\Modelsディレクトリ内のTrain.phpファイルを開き、既存のコードを以下のコードで置き換えます。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use JeroenG\Explorer\Application\Explored;
use Laravel\Scout\Searchable;
class Train extends Model implements Explored
{
use HasFactory;
use Searchable;
protected $fillable = ['title'];
public function mappableAs(): array
{
return [
'id'=>$this->Id,
'title' => $this->title,
];
}
}
上で追加したコードにより、Explorerを使用してTrain
モデル内のテキストを検索できます。
まとめ
LaravelとScoutのようなアドオンを活用すれば、高速で堅牢な全文検索機能を簡単に統合できます。データベースエンジン、コレクションエンジン、そしてMeilisearchとElasticsearchの機能を使用して、アプリケーションのデータベースと通信し、数ミリ秒単位の高度な検索メカニズムを実装しましょう。
シームレスにデータベースを管理、更新することで、コードをクリーンかつ効率的に保ちながら、優れたユーザー体験を提供することができます。
Kinstaのアプリケーション&データベースホスティングは、最新のLaravel開発における要件をすべて満たします。初月20ドル分は無料でご利用いただけます。
コメントを残す