LaravelからElasticsearchを使うときに理解しておいたほうがいいこと

# 前提条件

## 背景

Laravel × Elasticsearchに必要なライブラリを読み解くのに無駄に時間がかかったので共有。

## 環境

PHP 7.4

Laravel 6.2

Elasticsearch 7.8

## この記事を読んだ方がいい人

・MySQLの経験がある程度あってSQLってこんな感じだよねー、な感覚がある人。
・RDBでは遅くなってしまう検索を解決してくれるイケイケな道具があることを知りつつ、それがなんなのかよくわからない人。

## この記事を読まない方がいい人

・Elasticsearchの実務経験がすでにあって全文検索エンジンとマブダチな人。
・日本人ならGroongaにしろよ、って人。



# 必要なライブラリたち



## 1. Scout



### Scoutってなに

Laravelの標準ライブラリ。

よその全文検索機能とEloquentモデルの仲介役をする人。



この記事を見てる人はElasticsearchをLaravelから使いたい的な人が多いともうが、ScoutだけではElasticsearchに対応できるわけではない点に注意。



もう種類「エンジン」と呼ばれるモジュールが必要。



### インストール

好みの感じでモジュールをインストールする

・Github

```
git clone https://github.com/laravel/scout.git
```



・Composer

```
COMPOSER_MEMORY_LIMIT=-1 $(which composer) require laravel/scout
```

※メモリ不足対策で上限を外す。ローカル以外で実行するときは注意。



とりあえずこれだけでインストールは終わり。

いったい何がインストールされたのかざっくり解説



### モジュール概要

| ディレクトリ・ファイル   | 概要                                                         |
| ------------------------ | ------------------------------------------------------------ |
| Console /                | バッチ。DBに入ってるデータを一括インデックスしたり削除したりする処理が入ってる。 |
| Engines /                | 各検索エンジン(Elasticsearchとか他のやつ)を動かすためのモジュールの抽象クラスが入ってる。Algoliaだけはなぜか標準で作ってくれてある。でも今回は使わないから意味ない。 |
| Events /                 |                                                              |
| Jobs /                   |                                                              |
| Builder.php              | EloquentのBuilderっぽく作った全文検索エンジン向けのクエリを組み立てるためのクラス。 |
| EngineManager.php        | どのエンジンを使うかを管理するやつ                           |
| ModelObserver.php        | Eloquentに対してのCRUDが実行された時に、全文検索のインデックスにも反映されるようフックさせるためのクラス。 |
| Scout.php                |                                                              |
| ScoutServiceProvider.php | ServiceProvider。この中の処理を抜き取ってApp/Provider/AppServiceProviderとかに書いちゃってもいいし、Kernel.phpでこいつ呼び出しちゃっても良いんだと思う。 |
| Searchable.php           | 全文検索への処理メソッドが書いてあるトレイト。Scoutのなかの主役だと勝手に思ってる。これを書くEloquentモデルのクラスでuseする。 |
| SearchableScope.php      |                                                              |



### 実装

実装の手順はこの辺がとても参考になった。

https://qiita.com/sola-msr/items/64d57d3970b715c795f5



### 補足

ちなみにScoutの処理を詳しく追っていくと、非効率に感じる点があったので少し書いておく。



Scoutのデータ取得の処理は、ヒットしたデータのプライマリーキーを抜き出して

再度RDBにリクエストを投げている気がする。map() みたいな処理で。

toSearchableArray()でカスタマイズした情報とか、parent-childでうまく格納したデータとかも結局RDBから取り直す仕様になっている気がする。(ざっくりしか調べてないからそうじゃない方法があったら教えてください。)



この前提で行くとscoutの用途はあくまでも



RDBのLIKEでの部分一致でインデックスが効かずパフォーマンスガタ落ち！



っていうのを避けるためだけにあるように思える。RDBの補助で使ってね。みたいな。

検索系機能のデータ参照先を全部Elasticsearchに置き換えるような場合はscoutは使わずに自前で処理を作ったほうが良いのでは？



## 2. エンジン

### エンジンの選定

あれ、モジュール名じゃないの？



そうなんです。



Elasticsearchとの連動用モジュールは正規品があるわけではないんです。

じゃあ自分が作るの？っていうと優秀な先人たちが作ってくれてるのでそれを使うこともできます。

「laravel-scout-elastic」って調べるとみんなこの名前で作ってくれてます。

今回は2つ紹介。

・tamayo

https://github.com/ErickTamayo/laravel-scout-elastic

一応MITライセンスなので僕はこれを使いました。

`composer require tamayo/laravel-scout-elastic`

一応導入時はPHPやLaravelのバージョンにどのタイミングで対応したかなどを確認してStableそうなやつを導入しました。



企業プロジェクトで使う場合は、一応コピーレフトではないんですけどこれ使っていいですか的な確認はしたほうがいいかも。



・matchish

https://github.com/matchish/laravel-scout-elasticsearch

これも一応MIT。

特徴としては、複数のインデックスにまたがる検索処理を提供していること。

Elasticsearchはドキュメント型なので

このカラムとこのカラムでJOIN！　みたいなことはあまり想定されていないので

複数のインデックスにまたがるときはちょっとめんどくさい傾向にある。



なのでこれちょっと便利かなと思った次第。



まあそもそも設計段階でRDBとElasticsearchのインデックスの設計をちゃんとやっておけば

検索の瞬間にインデックスを跨ぐ、なんてことはしなくてもいいんだろうけど。



・あとは自分で作ってもいいらしい。



### 処理が気に食わないとき

採用して動かしてみたけど、細かい処理のところで、気に入らない処理が出てきたときは継承してカスタマイズする。



たとえばtamayoさんの場合はこんな構成になってる。

| ディレクトリ・ファイル          |                         |                                               |
| ------------------------------- | ----------------------- | --------------------------------------------- |
| Engines /                       |                         |                                               |
|                                 | ElasticsearchEngine.php | Scoutの抽象クラスのEngineを継承してきたやつ。 |
| LaravelScoutElasticProvider.php |                         |                                               |

このElasticsearchEngine.phpをExtendsしてApp/ 配下のどこかに置いちゃえば、処理を好き勝手カスタマイズしてバージョン管理にも含めることができる。



## 3. クライアント

接続用のクライアントモジュールは別で必要なのでインストールする。



`composer require elasticsearch/elasticsearch`

ここにはとくにドラマはない



# まとめ

コマンドやコーディング部分は先人の方の知恵がたくさんあったのですが、どこで何をしているかの理解の部分がコードを読むくらいしか方法がなくてしんどかったです。



同じような感覚の人はこの記事で是非ショートカットしてもらえればと思います。