Elasticsearch導入秘話
- #Elasticsearch
- #AWS
業務で行った検索ロジックをElasticsrachに置き換えた話について書きたいと思います。
Elasticsearchの導入前はRDBよりSQLを使って商品の検索ロジックを組み立てていました。
しかし商品数の増加に伴い
- より柔軟な検索の必要性
- ニーズに合った検索ロジックの実現
- 検索パフォーマンスの低下
といった課題が浮かび上がってきました。これらの課題をクリアするためElasticsearchの導入に至りました。
今回の記事では先日行ったElasticsearch導入について実際にどんなことをしたのか、ハマりポイントについて書きたいと思います。
Elasticsearchの導入にかかるインフラ
インフラとしてAWSを採択していました。DNS情報からサーバー、DBまで全てAWSのサービスを利用しています。
導入を決めた時点ではElasticsearchについてもAWS OpenSearchを利用する予定でした。
AWS OpenSearchはElasticsearchから派生したオープンソースプロジェクトであり、Elasticsearchとは別物です。AWS公式ドキュメントにもOpenSearchのロードマップはElasticsearchのロードマップと独立していると記載があるため、将来的にも違うものと考えていた方が良いと思います。
https://aws.amazon.com/jp/what-is/opensearch/
当初はOpenSearchでの構築を検討していましたが、今回の要望で利用したいElasticsearch用のプラグインがOpenSearchでは利用できないことが調査の過程で判明し、OpenSearchの利用はやめてEC2上にElasticsearchを構築することにしました。
EC2上で構築する場合、クラスタの設定や監視の設定も独自で行う必要があります。そのため初期コストは比較的高いと感じます。
事前に使いたいプラグインがOpenSearchに対応しているか確認することや本当にEC2で運用する方が良いのか検討をすることが大切だと思います。
※余談ですがAWS OpenSearchでもKibanaのようなサービスとしてOpenSearch DashboardsがありGUIで操作が可能となっています。
今回の導入で実現したかったこと
次にElasticsearchを導入することで期待していたことについてです。
検索のデータを見ていると、検索ワードによる揺れにより上手く検索結果が表示されていないケースが多くありました。
例)
- 「お出かけ」と検索したときに、商品名に「おでかけ」とひらがなで入っていると当たらなくなるというもの
- 「・」(中黒) が商品名に入っているとつなげたキーワードで当たらなくなるというもの
- また、同義語での検索についてもうまく検索できないというケースがありました。例)
- 「釣り」と「フィッシング」で検索結果が大きく異なる
- 「映画館」と「シネマ」で検索結果が大きく異なる
このような検索揺れを改善することで検索精度の向上を目指すというのが大きな目的でした。
同義語については、同義語辞書をメンテナンスしていくことも検討しましたが、辞書のメンテナンスは想像以上に時間とコストがかかります。
同義語辞書の難しさはサービスにおいて同義語となるものとならないものが変わるケースがあることだと思います。一般的に「医者」と「病院」は同義語ではありませんが、検索においては「医者」と「病院」は同義語とみて検索した方が検索の揺れという観点では少なくなります。
このような問題が際限なく発生するため同義語辞書のメンテナンスは非常に困難だと考えました。
当初はAWS OpenSearchでも利用できる kuromoji という辞書を利用することを検討していましたが、検索に当てはめてみるとイマイチしっくりこないという状態でした。
微妙な検索の調整をするためにユーザー定義辞書という自分たちで設定した辞書を適用することもできたのですが、コストがかかりすぎます。
そこで、辞書については kuromoji ではなく、別の辞書を利用することにしました。利用している辞書はsudachi-dictというものでGithubで公開されています。※こちらの辞書はAWS OpenSearchでは使うことができません。(導入段階では)
https://github.com/WorksApplications/SudachiDict
また、n-gramによる検索手法も取り入れました。これにより、ヒット件数の母数を増やすことができます。n-gramで設定する分割の閾値は小さすぎるとノイズが多くなりかえって検索精度を低下させる可能性がありますが、適切な値に調整することで、例えば「・」のような問題に対応することが可能です。
このようにして検索をElasticsearchにリプレイスしました。
ハマりポイント
次にハマりポイントについてです。
1つ目は、EC2上でのElasticsearchクラスタの構築です。
クラスタを構築するためにはEC2インスタンス間での連携が必要となります。また、Elasticsearchはデータを保持するため、できる限りプライベートな環境に配置することが望まれます。
複数のEC2インスタンスは同一ネットワークに存在しているためプライベートな環境でも連携は問題ないはずなのですが、なかなか連携できずハマりました。よく調べてみるとAWSのネットワークの問題より、Elasticsearchの公式よりEC2用のプラグインを使う必要があるとのことでこちらを使い連携をしました。
https://www.elastic.co/docs/reference/elasticsearch/plugins/discovery-ec2
2つ目は、Elasticsearchに Master-Slaveの概念がないことです。
Elasticsearchの場合、1台が決まってMasterになるのではなく、クラスタを形成しているノードの中でMasterを選出する投票が行われ、Masterノードができるという仕組みをとっています。※そのため、エンドポイントにも工夫が必要です。
また、投票形式のため2台構成ではHA構成にはなりません。この点も注意が必要だと思います。
先にこの仕組みを知らなかったために後からインフラ構成を変更することになってしまったので、先に調べておくことが大切だと思います。
導入後の成果
今回、Elasticsearchを導入したことにより検索のパフォーマンスについても改善がみられました。
ALBのレスポンスタイムが常時0.5秒を超えていたような状態から現在は0.1秒を切る程度に安定しています。これはElasticsearchに変更したことでDBへの負荷を削減することができたためと考えています。
ALB平均レスポンスタイム
最後に
今回は先日実施したElasticsearchの導入についてでした。
検索をリプレイスすることは簡単ではありませんが、検索の精度はとても重要な機能の一つです。これからもより検索しやすく、求めているものが見つかる検索を目指していきたいと考えています。