見出し画像

[laravel] meilisearchを試してみました

laravel news にlaravel scoutがmeilisearchに対応したと書いてあったので、今回試したみました。

meilisearchとは?

オープンソースで高速な全文検索できるサーチエンジン。サーチ時のタイポにも対応している。

Laravelインストールしてからデータ挿入

laravel インストール

$laravel new meilisearch-test

プロジェクトのディレクトリに移動

$cd meilisearch-test

データベースを作成するためにmysql にログイン(ここは環境に依存)

$mysql -uroot -p

データベースを作成 (.envファイルのDB_DATABASEと同じにするとスムーズ)

mysql> create database meilisearch_test;

データベースを作ったらmysqlからexit

mysql> exit

migrateでデフォルトのテーブルを作成します。

$php artisan migrate

4つのテーブルができています。

スクリーンショット 2021-05-20 20.16.05

usersテーブルで確認していきたいので、usersテーブルに300行のデータを挿入します。

database/seeders/DatabaseSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
   /**
    * Seed the application's database.
    *
    * @return void
    */
   public function run()
   {
       \App\Models\User::factory(300)->create();
   }
}

以下のコマンドで挿入の実行

$php artisan db:seed

tableplusでもデータが入っていることを確認。

スクリーンショット 2021-05-20 20.18.28

meilisearchインストール

macにインストール

$brew update && brew install meilisearch

起動

$meilisearch
Server listening on: "http://127.0.0.1:7700"

laravel scoutの設定

プロジェクトのディレクトリにて。

scoutインストール

$composer require laravel/scout

scoutのコンフィグファイルをpublish

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

今回はUserモデルを使うのでUserモデルに

Laravel\Scout\Searchable traitを追加しSearchableもuseする。

app/Models/User.php

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Scout\Searchable;

class User extends Authenticatable
{
   use HasFactory, Notifiable, Searchable;

meilisearchドライバーを使う時に必要なパッケージをインストール

$composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle

.envファイルに以下を追加

SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700

検索できるデータを制限

Userモデルにはすでにhiddenプロパティでpasswordとremember_tokenが定義されているのでインデックスされません。

protected $hidden = [
       'password',
       'remember_token',
   ];

今回はusersテーブルのupdated_atカラムをインデックスさせないようにすることにします。そのためにUserモデルにtoSearchableArrayメソッドを追加します。

app/Models/User.php

public function toSearchableArray()
{
       $array = $this->toArray();

       unset($array['updated_at']);

       return $array;
}

unsetを使ってupdated_atを除きました。

インポート

今回のように既に存在するテーブルをインデックスする場合はデータをインポートする必要があります。

次のコマンドでインポート

php artisan scout:import "App\Models\User"

ブラウザで確認

http://127.0.0.1:7700/ で確認

スクリーンショット 2021-05-20 20.57.08


tinkerでデータ追加

日本語データを追加してみる。

$php artisan tinker
Psy Shell v0.10.8 (PHP 8.0.3 — cli) by Justin Hileman
>>> $user = new User;
[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
=> App\Models\User {#3385}
>>> $user->name = "たなかたろう";
=> "たなかたろう"
>>> $user->email = "tanaka@test.com";
=> "tanaka@test.com"
>>> $user->password = bcrypt('tanaka_password');
=> "$2y$10$Op0Eb0FkY5c67Gs.6IZPTeSOfvdLplFqTCJHf6a0GXNEXaOPQmfdG"
>>> $user->save();
=> true

追加直後にすぐ更新されています。(300から301になっている)

スクリーンショット 2021-05-20 21.05.27

javascriptで実際に使ってみる

サーバーを立ててサイトを表示。

$php artisan serve

スクリーンショット 2021-05-20 21.08.26

laravelをインストールしたばかりでwelcomeページが出ているのでこのページ(welcome.blade.php)を変更していきます。

参考ページ

検索フォームを作成

   <div>
       <input type="text" id="search">
       <div id="results" style="margin-top:50px"></div>
   </div>

CDNを使用します。

<script src='https://cdn.jsdelivr.net/npm/meilisearch@latest/dist/bundles/meilisearch.umd.js'></script> 

そのあとindexを取得し、

   <script>
       const client = new MeiliSearch({
           host: 'http://127.0.0.1:7700',
       })
       const index = client.index('users')

   </script>

検索フォームのインプットのkeyupイベントを使い、入力した文字列で検索します。

           const input = document.querySelector('#search')

           input.addEventListener('keyup', event => {
               index.search(event.target.value)
               .then(response => {
                       let nodes = response.hits.map(user => {
                           let div = document.createElement('div');
                           div.textContent = user.name;
                           return div;
                       });
                       let results = document.querySelector('#results');
                       results.innerHTML = '';
                       results.append(...nodes);
                   })
           })

​試してみます

見た目はフォームのみ

スクリーンショット 2021-05-24 19.18.16

このフォームに入力してみると

vlc-record-2021-05-24-19h23m21s-画面収録 2021-05-24 19.21.53.mov-.mp4

日本語を入力しても

vlc-record-2021-05-24-19h29m16s-画面収録 2021-05-24 19.28.38.mov-.mp4

タイポにも対応している。

完成形のファイルはこちら




この記事が気に入ったらサポートをしてみませんか?