自分だけのクイズ作成 - Quipha公開中

【Laravel Scout】Meilisearchを使って全文検索を実装

Laravel
スポンサーリンク

検索

Meilisearchで確認

Meilisearchのダッシュボードで、検索ワードを指定して検索してみましょう。
非常に高速に検索結果が返ってきます。

Laravelで実装

web.phpに検索結果を返却する処理を追加します。
「ex」という文字列を検索して、Scoutを通じてMeilisearchから検索結果を取得します。

routes\web.php
use App\Models\Post;

Route::get('/search', function () {
    $posts = Post::search('ex')->get();  
    return $posts;
});

以下のURLにアクセスします。

http://localhost/search

応答結果を確認します。

もちろん日本語でも検索ができます。
Meilisearchの検索結果と同じ結果のJSONを取得することができました。

JSONの日本語を表示するために、Firefoxで確認しました。

データの登録・変更・削除

登録

モデルにSearchableを追加していますので、普通にDBに登録する処理でインデックスに登録できます。

use App\Models\Post;

$post = new Post;

$post->title = "タイトルです";
$post->body = "本文です";

$post->save();

DBに登録と同時に、インデックスにも登録されます。

インデックスを作成する条件を指定できます。
例えば、公開日が設定されているデータのみ、インデックスに登録することができます。

モデルを修正して、shouldBeSearchable関数を実装します。
以下のコードでは、公開日が設定されている場合にのみ、インデックスに登録できます。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Post extends Model
{
    use HasFactory;
    use Searchable;

    /**
     * 公開しているかどうか
     * 
     * @return bool
     */
    public function isPublished()
    {
        return !is_null($this->published_at);
    }

    /**
     * モデルを検索可能にする判定
     *
     * @return bool
     */
    public function shouldBeSearchable()
    {
        return $this->isPublished();
    }
}

saveなどで登録する際に適用されます。

変更

更新も通常通りの処理で、インデックスも更新されます。

use App\Models\Post;

$post = Post::find(101);

$post->title = "タイトル更新です";
$post->body = "本文更新です";

$post->save();

インデックスも更新されます。

削除

削除も同様で、以下のようなコードでインデックスから削除されます。

use App\Models\Post;

$post = Post::find(101);
$post->delete();
スポンサーリンク

APIキーの設定

Sailは標準でMeilisearchが使えるようになっていますが、マスターキーやAPIキーが設定されていないため、誰でも操作可能です。

開発で使う分には問題ありませんが、マスターキーを設定してみましょう。

docker-compose.ymlを修正します。
MEILI_MASTER_KEYを追加し、マスターキーを指定します。
‘master_key’という文字列を指定していますが、任意の文字列を指定してください。

    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
        environment:
            MEILI_MASTER_KEY: 'master_key'

docker-compose.ymlを変更後、Sailを再起動します。

Meilisearchのダッシュボードを開いてみましょう。
マスターキーを入力して、データにアクセスできるようになります。

マスターキーを追加すると、自動的に二つのキーが追加になります。

  • Default Search API Key (検索用APIキー)
  • Default Admin API Key (管理用APIキー)

以下のコマンドを実行し、APIキーを確認します。
‘master_key’はマスターキーを指定します。

$ curl \
  -X GET 'http://localhost:7700/keys' \
  -H 'Authorization: Bearer master_key'

以下のようなJSONデータが取得できました。
“key”という項目がAPIキーになります。

{"results":[
{"name":"Default Search API Key","description":"Use it to search from the frontend","key":"xxxxxxx","uid":"xxxxxxx","actions":["search"],"indexes":["*"],"expiresAt":null,"createdAt":"2022-10-19T13:33:29.943963186Z","updatedAt":"2022-10-19T13:33:29.943963186Z"},
{"name":"Default Admin API Key","description":"Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend","key":"xxxxxxx","uid":"xxxxxxx","actions":["*"],"indexes":["*"],"expiresAt":null,"createdAt":"2022-10-19T13:33:29.934972068Z","updatedAt":"2022-10-19T13:33:29.934972068Z"}
],"offset":0,"limit":20,"total":2}

.envに、Default Admin API Keyのkeyを指定します。

MEILISEARCH_KEY=xxxx

APIキーを追加した場合は、モデルの保存時に正常にインデックスに登録できます。
ただしAPIキーが間違っている場合は、以下のエラーが表示されます。

The Authorization header is missing. It must use the bearer authorization method.

検索だけの権限が必要であれば、Default Search API Keyを使用しましょう。

APIキーによるアクセス制限ができますので、詳しくは公式サイトをご覧ください。

Master key and API keys
Open source Instant Search Engine

データベースエンジンを使う

今回はLaravel Scoutを使いエンジンにMeilisearchを使いましたが、データベースを使用することもできます。

まずは、Meilisearchをエンジンとしている場合、どのようなSQL文を発行しているのか確認してみましょう。

\DB::enableQueryLog();

$posts = Post::search('赤')->get();

\Log::debug(\DB::getQueryLog());

ログファイルを確認しましょう。
IN句にIDを指定して検索していました。
ScoutはMeilisearchの検索結果からIDだけを取得し、Eloquentで取得し直している感じでしょうか。

[2022-10-19 13:48:41] local.DEBUG: array (
  0 => 
  array (
    'query' => 'select * from `posts` where `posts`.`id` in (89, 53, 90, 92, 41, 72, 52, 36, 38, 76, 98, 20, 1, 37, 84, 10, 91, 99, 97, 2)',
    'bindings' => 
    array (
    ),
    'time' => 2.76,
  ),
) 

次に、エンジンをデータベースに変更してみます。
.envを修正します。

SCOUT_DRIVER=database

これにより、Meilisearchは使用されず、データベースのみ使用されます。

モデルを修正し、以下を追加します。
検索対象の項目を指定します。

app\Models\Post.php
    /**
     * モデルに対するインデックス可能なデータの配列を取得
     *
     * @return array
     */
    public function toSearchableArray()
    {
        return [
            'title' => $this->title,
            'body' => $this->body,
        ];
    }

先ほど同様、検索を行いログを確認しました。
Like検索で直接データベースから検索していることが分かります。

[2022-10-19 14:04:20] local.DEBUG: array (
  0 => 
  array (
    'query' => 'select * from `posts` where (`posts`.`title` like ? or `posts`.`body` like ?) order by `id` desc',
    'bindings' => 
    array (
      0 => '%赤%',
      1 => '%赤%',
    ),
    'time' => 3.02,
  ),
) 

開発環境にMeilisearchが用意できない場合など、とりあえずデータベースでLaravel Scoutを介した実装を行うのに使えると思います。

ただのLike検索ですので、大量データの全文検索ではパフォーマンスが悪いと思いますが、本番環境ではMeilisearchに入れ替える、といった使い方ができると思います。

その他

初学者へ

Laravelを初めて触る方へ向け、手順やアドバイスをまとめました。

外部サーバーへ公開

作成したアプリは公開して使ってもらいましょう!
Laravelアプリケーションを外部公開する方法をまとめました。

脆弱性対策

脆弱性を抱えたアプリケーションの場合、攻撃を受ける可能性があり大変危険です。
作成したアプリケーションは、脆弱性対策も意識しましょう。

GitHubと連携

GitHubと連携する方法を解説しました。
プロジェクトの管理はGitHubを活用しましょう。

さいごに

今回は、Laravel Scoutを使い、検索エンジンにMeilisearchを使用して実装を行いました。
是非、全文検索を実装する際に参考にしてください。

他にも私のブログで、Laravelについて解説している記事がありますのでご覧ください。

\オススメ/

コメント

タイトルとURLをコピーしました