PHPを使ってOpensearchで日本語検索してみた

2021年11月に中途入社した砂原です。バイトルやはたらこねっとなどのHR系サービスの開発を担当している部署に所属しており、社内の技術的な課題や困りごとを調査・検証するようなお仕事をしています。
弊社では現在PostgreSQLを検索基盤として利用しているのですが、今後サイト内検索の利便性を高めていくためにPostgreSQLに変わるものはないかと調査・検証しています。
その中でも今回はOpenSearchを使ってみた系の話を書こうと思います。
OpenSearchについて
OpenSearchの詳しい解説はAWS様のドキュメントにも詳しく書いてあるので割愛します。
一般的にRDBはフリーワード検索や各種集計があまり得意ではないのですが、OpenSearchはその辺りの検索速度や利便性がかなり向上します。
また、Amazon OpenSearch Serviceを使えばかなり容易に検索基盤が構築できるので、もしRDBで検索機能を実現しているが「サイト内検索が遅い」「集計が遅い/もっといい感じの集計をしたい」などあれば、一度試してみる価値があると思います!
ということで、本記事はOpenSearchに触れる第一歩として、Dockerを用いて手元でOpenSearchを動かす手順を取り上げます。
バージョンは執筆時点(2022/6末)で最新が2.0.1なのですが、本記事では2.0.0を取り扱っています。
Dockerを使ってOpenSearchを立ち上げる
手元でサクッと動かす分には1ノードでも良いかと思うので、公式ドキュメントから少し変更しています。こちらはクラスメソッド様の記事を参考にさせていただきました。ありがとうございます!
version: '3'
services:
opensearch:
build:
context: .
dockerfile: Dockerfile
container\_name: opensearch
environment:
- cluster.name=docker-cluster
- node.name=opensearch-node
- cluster.initial\_master\_nodes=opensearch-node
- bootstrap.memory\_lock=true
- http.host=0.0.0.0
- transport.host=127.0.0.1
- "OPENSEARCH\_JAVA\_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- $PWD/.data/opensearch:/usr/share/opensearch/data
ports:
- 9200:9200
networks:
- opensearch-net
opensearch-dashboards:
image: opensearchproject/opensearch-dashboards:2.0.0
container\_name: opensearch-dashboards
environment:
OPENSEARCH\_HOSTS: "https://opensearch:9200"
ports:
- 5601:5601
networks:
- opensearch-net
volumes:
opensearch-data:
networks:
opensearch-net:
Dockerfile内で日本語検索に必要なpluginをインストールします。/tmpに一度ダウンロードしているのですが、直接インストールしてもいいかと思います。
FROM opensearchproject/opensearch:2.0.0
# Download Plugin Files
RUN curl -L -k -O https://artifacts.opensearch.org/releases/plugins/analysis-kuromoji/2.0.0/analysis-kuromoji-2.0.0.zip --output-DIR /tmp
RUN curl -L -k -O https://artifacts.opensearch.org/releases/plugins/analysis-icu/2.0.0/analysis-icu-2.0.0.zip --output-dir /tmp
# Install Plugin
RUN /usr/share/opensearch/bin/opensearch-plugin install file:///tmp/analysis-kuromoji-2.0.0.zip
RUN /usr/share/opensearch/bin/opensearch-plugin install file:///tmp/analysis-icu-2.0.0.zip
docker compose -d up を実行します。
これで準備は完了です!
OpenSearch環境の確認
Dashboard
http://localhost:5601/ にアクセスできればOKです。
なお、初期USER/PASSは admin/admin です。
OpenSearch
https://localhost:9200/ にアクセスし、以下のようなOpenSearchの情報が表示されればOKです。
こちらも初期USER/PASSは admin/admin です。
{
"name" : "opensearch-node",
"cluster\_name" : "docker-cluster",
"cluster\_uuid" : "2fGiy\_Q2QsqIRIrfv6Luiw",
"version" : {
"distribution" : "opensearch",
"number" : "2.0.0",
"build\_type" : "tar",
"build\_hash" : "bae3b4e4178c20ac24fece8e82099abe3b2630d0",
"build\_date" : "2022-05-19T00:26:04.115016552Z",
"build\_snapshot" : false,
"lucene\_version" : "9.1.0",
"minimum\_wire\_compatibility\_version" : "7.10.0",
"minimum\_index\_compatibility\_version" : "7.0.0"
},
"tagline" : "The OpenSearch Project: https://opensearch.org/"
}
次はPHPでOpenSearchを操作してみましょう。
OpenSearch-phpの利用方法
1.composerをインストールする
2.composerにopensearch-phpを追加する
composer require opensearch-project/opensearch-php
3.サンプルスクリプトを用意しました。こちらを実行して動けばOKです。
サンプルスクリプトの処理は以下の通りです。
・prとnameいうフィールドをもつtest-indexという名前のインデックスを作成(prはkuromojiを利用するよう設定)
・prフィールドに対して京都というワードで全文検索
・検索結果を表示(東京都はHITせず、京都だけがHITする)
<?php
require \_\_DIR\_\_ . '/vendor/autoload.php';
// 環境によって適宜変更してください
$opensearchHost = \[
'host' => 'localhost',
'scheme' => 'https',
'port' => '9200'
\];
$user = 'admin';
$pass = 'admin';
$indexName = 'test-index';
$client = (new \\OpenSearch\\ClientBuilder())
->setHosts(\[$opensearchHost\])
->setBasicAuthentication($user, $pass)
->setSSLVerification(false)
->build();
// index作成
$indexParams\['index'\] = $indexName;
$exists = $client->indices()->exists($indexParams);
if (!$exists) {
$client->indices()->create(\[
'index' => $indexName,
'body' => \[
'settings' => \[
'index' => \[
'analysis' => \[
'analyzer' => \[
'kuromoji' => \[
'type' => 'custom',
'tokenizer' => 'kuromoji\_tokenizer'
\]
\]
\]
\]
\],
'mappings' => \[
'properties' => \[
'pr' => \[
'type' => 'text',
'analyzer' => 'kuromoji'
\],
'name' => \[
'type' => 'text'
\]
\]
\]
\]
\]);
}
// データ作成
$client->create(\[
'index' => $indexName,
'id' => 1,
'body' => \[
'name' => '田中一郎',
'pr' => '京都に10年住んでいます。'
\]
\]);
$client->create(\[
'index' => $indexName,
'id' => 2,
'body' => \[
'name' => '山田花子',
'pr' => '東京都出身です。'
\]
\]);
// データ検索
$result =(
$client->search(\[
'index' => $indexName,
'body' => \[
'\_source' => \['name','pr'\],
'query' => \[
'match' => \[
'pr' => '京都'
\]
\]
\]
\])
);
var\_dump($result)
※環境によってはデータ作成後にsleepを数秒入れないと正しく結果が取得できないかもしれません。
以上がDockerを用いて手元でOpenSearchを動かす手順となります。
最後に
OpenSearchはElasticsearch7.10.2から派生したという経緯があるため、もし実装にあたり困ったことが発生した場合はElasticsearch-PHPのドキュメントも参考にすると答えが見つかるかもしれません。
検証時にOpenSearch×PHPのサンプルがなかなか見つからず苦労したので、記事にしてみました。お役に立てると嬉しいです。
Discussion