こんにちは!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のメンバーがブログを投稿していきます!
レイスシステムソリューションズ株式会社のソフトウェア開発や、
採用に関するお問い合わせについては、下記のリンクにてお問い合わせください。
-1.png)



