シンクロ・フード エンジニアブログ

飲食店ドットコムを運営する、株式会社シンクロ・フードの技術ブログです

求人飲食店ドットコムの求人検索に OpenSearch を導入した話

こんにちは、シンクロ・フードの小室です。

シンクロ・フードでは弊社のサービスである求人飲食店ドットコムの求人検索にOpenSearchを導入しました。
どのように導入したか、また、導入した結果を紹介します。

opensearch.org

はじめに

今回、求人検索にOpenSearchを導入した目的は検索の高速化です。
また、今後求人の掲載数が増加したときにも検索性能を劣化させないことも求められていました。
そのため、MySQLよりもOpenSearchの方が大量のデータ検索に向いていることも採用した理由にあります。

同様の検索エンジンとしては、OpenSearch以外にもApache SolrやElasticsearch等が選択肢としてありました。
しかし、今回は主に運用の負荷を減らすため、AWSのマネージドサービスも提供されているOpenSearchを採用しました。

以前の求人検索

求人の検索に使用される情報はMySQLに保存されており、それに対して検索が行われていました。
そのため、OpenSearchで検索を行える状態にするためにはMySQLからOpenSearchへデータを同期する必要がありました。
また、これらのデータは複数のアプリケーションから更新されるため、このことを念頭に、OpenSearchへのデータの同期方法を考えました。

MySQLからOpenSearchへのデータの同期方法

データの同期を行うシステムの構成図は以下のようになっています。

データ同期システム構成図

各アプリケーションではデータが更新される箇所で更新が行われたレコードの主キーをSNSへ送信します。
rakeタスクではSQSをポーリングし、受け取った主キーを元にMySQLからインデックスの作成に必要な情報を取得しOpenSearchに対して更新を行います。

当初は定期的に更新を実行することを考えていましたが、よりリアルタイムに更新を行うためにこの方法を採用しました。
また、この方法ではデータの更新が行われるアプリケーションではメッセージをSNSへ送信するだけであるため、定期的に更新する場合と同様に更新処理の実装は一箇所で済み、実際の更新処理について各アプリケーションは意識しなくていいというメリットがあります。

OpenSearchによる検索

求人の検索は各種条件を元にOpenSearchに対して行います。
OpenSearch からは一致したものの主キーを取得し、MySQLから実際の表示に必要なデータを取得しています。

また、既存のフリーワード検索ではLIKEによる部分一致を行っており、この検索をOpenSearchで再現する必要がありました。
これはN-gram Tokenizerを使用し、検索クエリに match_phrase句(通常使用される match 句と異なり、文字列の出現する順番が考慮される)を使用することで実現できました。

また、icu_normalizerという文字の正規化を行うフィルターを使用することで、既存ではできなかった丸数字(①、…)と数字(1、…)、半角カナ(ア、…)と全角カナ(ア、…)等で区別せず検索できるようになりました。

テスト中に発生した問題

インデックスの更新に関して、ローカルでの開発中には起きず、テスト環境だけで起きた問題が主に2つありました。

1つ目はアプリケーションで行った変更が反映されていない古いデータでOpenSearchのインデックスが更新される問題でした。
具体的には、rakeタスクでデータを再取得するときに古いデータが取得され、そのデータで更新がされている状態でした。
この原因としてはトランザクションの中でSNSへのメッセージ送信を行っていることでした。
これはアプリケーションで自動的に張られるトランザクションについて把握できていなかったためにそのような実装にしてしまっていました。
この問題が確認できていないときは、たまたま、rakeタスクで更新処理が起きるまでの間にコミットされていて更新が成功している状態でした。トランザクションを明示的に張り、コミット後にSNSへメッセージを送信するように修正しました。

2つ目は、更新の負荷によって429エラーが起きていた問題です。
429エラーは、OpenSearchに対するリクエストが増え、処理が追いつかない場合に起きるようです。
この問題はローカルでOpenSearchのDockerイメージを利用して開発をしているときには確認できず、テスト環境でAmazon OpenSearch Serviceを利用して初めて確認できました。
今回は偶発的に(多数の更新が重なり)エラーが起きた場合には更新処理のリトライで対処をしました。
rake タスクでエラーが起きた場合に SQS へメッセージを戻して、再度処理を行っています。
その他ではバッチ処理で大量の更新をする場合もエラーが起きるため、こちらは個別に対処しました。
ここでのバッチ処理ではリアルタイム性は比較的求められていなかったため、更新を小分けに行いスリープを挟むことで負荷を軽減させています。

aws.amazon.com

導入した結果

1月12日に無事にリリースが完了しました。
以下はフリーワード検索と業態(イタリアン)の検索のレスポンスタイムの推移です。

レスポンスタイム

リリースの前後で、フリーワード検索で、平均510ms減り、業態(イタリアン)の検索では平均171ms増えました。
フリーワード検索では、テスト環境でも同様にフリーワード検索が速くなり、それ以外では既存と同等もしくは遅くなっているという結果になっており想定内ではありました。

この原因は単純な一致の検索だとMySQLで十分に速いというのとOpenSearchではアプリケーションとはREST APIでやり取りをするためMySQLよりも通信に時間がかかるためだと考えています。
これを改善するため、今後OpenSearchに対する複数のリクエストをまとめる等の対策を行っていきます。

まとめ

求人検索の高速化を目的にOpenSearchを導入しました。
更新方法をリアルタイムに近づけるためにSNS/SQSを使用したり、既存のLIKE検索を再現するために工夫したりしました。また、テスト環境で起きた問題に対処しました。

今回の目的である検索の高速化については、フリーワード検索ではレスポンスが速くなり、大きかったMySQLへの負荷も軽減できました。しかし、他の検索条件ではまだ効果が出ていません。
これは今後リクエストをまとめる等の対策で改善していきたいと考えています。

OpenSearchについては今回初めて導入したということで、分かっていないことも多いです。
今後、知見を深めより活用していきたいと思います。


最後に、エンジニア募集のお知らせです!
シンクロ・フードでは、まだまだ技術的な課題やチャレンジが残っています。
ぜひ、一緒に改善していきましょう!

また、飲食店ドットコム、求人飲食店ドットコムを始めとしたサービスの開発・改善も、どんどん進めております。
ご興味のある方は、以下の採用サイトからご連絡ください! www.synchro-food.co.jp