LaravelでElasticsearchを使ってみた

目次

こんにちは!RSSでWEBアプリケーションの開発を行っているM.R.です。
今回は、「LaravelでElasticsearchを使ってみた」についてお話しします。
このテーマに興味を持った背景や体験談を少し共有したいと思います。

なぜこのElasticsearchを選んだのか

近年、ビッグデータの時代が到来し、より効率的なデータ検索が求められるようになりました。その中でもElasticsearchは、スピーディかつ強力なフルテキスト検索を実現するための優れたツールです。Laravelが提供する柔軟性と組み合わせることで、より使いやすく、パフォーマンスの高いアプリケーションを構築できる点に魅力を感じました。また、もともと別のプロジェクトでもElasticsearchを触ったことがあったため、その経験を活かしてやってみよう!と思ったことがElasticsearchを使ってみることにした理由です。

Elasticsearchの環境設定

LaravelでElasticsearchを使うためには、まずは開発環境にElasticsearchとKibanaを導入する必要があります。以下は、環境情報とDockerを使用した設定手順です。

環境情報

PHP: 8.1.2
Laravel: 9.35.1
MySQL: 8.0
Ubuntu: 20.04.4
Composer: 2.4.3
Vue.js: 3.2.36

以下のようなYAMLファイルを使って、Docker Composeでこれらのサービスを立ち上げます。


version: '3'
services:
 elasticsearch:
image: elasticsearch:8.0.0
environment:
- discovery.type=single-node
ports:
 - '9200:9200'
kibana:
image: kibana:8.0.0
ports:
- '5601:5601'
environment:
ELASTICSEARCH_URL: http://elasticsearch:9200

インデックスの作成

次に、検索したいデータを格納するためのインデックスを作成します。このステップでは、Kibanaの開発者用コンソールを使って、具体的なクエリを実行します。

以下のクエリを使用して、全文検索用のインデックスを作成します:

//全文検索用インデックス作成クエリ
PUT /full_text_index
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  },
  "mappings": {
    "properties": {
      "quarter_name": {
        "type": "text"
      },
      "user_id": {
        "type": "text"
      },
      "user_name": {
        "type": "text"
      },
      "year": {
        "type": "text"
      },
      "grade": {
        "type": "text"
      },
   ※中略※
    }
  }
}

以下のクエリでテストデータを作成しました。

//インデックスにPOST
POST /full_text_index/_doc/
{
 "quarter_name": "27期3Q",
 "user_id": "test_tarou",
 "user_name": "テスト太郎",
 "year": "2024",
 "grade": "A",
 "division_name": "システム開発部",
 "section_name": "開発課",
 "team_name": "開発Aチーム",
 "project_name": "社内システム開発",
 "system_name": "案件管理システム",
 "system_info": "社内専用の案件管理システム",
 "system_skills": "Laravel,Next.js,Tailwindcss",
 "affliation": 6,
 "position_name": "プロジェクトメンバー",
 "outcome": "社内専用の案件管理システムをSPAで作成した",
 "learned": "Nextを使い、はじめてSPAで作成した"
}



検索メソッドの実装

LaravelでElasticsearchを使用する際、Laravel Scoutが便利ですが、今回は複数テーブルにわたる検索のため、直接Elasticsearchに接続する方法を選びました。

まず必要なライブラリをインストールします。

composer require elasticsearch/elasticsearch

次に環境設定ファイル(.envや.config)にElasticsearchに接続するための設定を追加します。

//.envに追加

ELASTICSEARCH_HOSTS='http://techbook-elasticsearch-1:9200'
ELASTICSEARCH_INDEX=techbook_full_text_index
ELASTICSEARCH_ENABLED=true
//config/app.phpの最後に追加

    //Elasticsearchの設定
    'elasticsearch' => [
        'index' => env('ELASTICSEARCH_INDEX', 'laravel'),
        'hosts' => [
            env('ELASTICSEARCH_HOSTS', 'http://localhost:9200'),
        ],
    ],

次に、検索を呼び出すコントローラーとサービスクラス、リポジトリを作成します。

FullTextSearchController.php

<?php

namespace App\Http\Controllers;

use Inertia\Inertia;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Log;
use App\Services\FullTextSearchService;

class FullTextSearchController extends Controller
{
    private $full_text_search_service;

    public function __construct(
        FullTextSearchService $full_text_search_service,
    ){
        $this->full_text_search_service = $full_text_search_service;
    }

    //検索ボタンを押したら
    public function search(Request $request)
    {

        if ($search_words_array['free_search'] && !empty($search_words_array['free_search'])) {
            $free_result = $this->full_text_search_service->freeSearch($search_words_array['free_search']);
        } else {
            $free_result = [];
        }

        return $free_result;
    }

}

FullTextSearchService.php

<?php

namespace App\Services;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Lang;
use App\Repositories\Search\FullTextSearchRepositoryInterface;

class FullTextSearchService
{
    private $full_text_search;

    public function __construct(
        FullTextSearchRepositoryInterface $full_text_search
    ) {
        $this->full_text_search = $full_text_search;
    }

    /**
    *  全文検索用のメソッド
    *  @param array
    */
    public function freeSearch($search_words)
    {
        $hit_data = [];
        foreach ($search_words as $word) {
            $result = $this->full_text_search->fullTextSearch($word);
            $hit_data = $result;
        }

        return $hit_data;
    }

}

FullTextSearchRepositoryInterface.php

<?php
namespace App\Repositories\Search;

use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;

interface FullTextSearchRepositoryInterface
{
    /**
     * Repositoryのメソッドを定義する
     *
     * @return Collection
     */
    public function fullTextSearch(string $search_words);
}

FullTextSearchRepository.php

<?php
namespace App\Repositories\Search;

use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Elastic\Elasticsearch\ClientBuilder;
use Illuminate\Support\Facades\Config;

class FullTextSearchRepository implements FullTextSearchRepositoryInterface
{
    public function fullTextSearch($search_words)
    {
        $client = ClientBuilder::create()
                    ->setHosts(Config::get('app.elasticsearch.hosts'))
                    ->build();

        $params = [
            'index' => Config::get('app.elasticsearch.index'),
            'body' => [
                'query' => [
                    'query_string' => [
                        'query' => $search_words
                    ]
                ]
            ]
        ];

        $response = $client->search($params);
        $dataArray = [];
        if (isset($response['hits']['hits'])) {
            foreach ($response['hits']['hits'] as $hit) {
                $dataArray[] = $hit['_source'];
            }
        }

        return $dataArray;
    }
}

最後に作成した検索機能をAPIテストツールなどから実行してみます。
実行してみると以下のような結果が返ってきました。
Next.jsを使ったテスト太郎さんの経歴を取得することができました。

まとめ

今回の記事では、LaravelとElasticsearchを使って検索機能を実装する流れをご紹介しました。検索機能の実装は、アプリケーションの使い勝手を大きく向上させる要素となるため、是非挑戦してみてください。

おわりに

最後まで読んでくださってありがとうございました。
これからもRSSのメンバーがブログを投稿していきます!

レイスシステムソリューションズ株式会社のソフトウェア開発や、
採用に関するお問い合わせについては、下記のリンクにてお問い合わせください。

お問い合わせ