検索エンジンを Amazon CloudSearch から Elasticsearch に乗り換えた 3 つの理由

elasticsearch-logo-color-h

こんにちは。Tokyo Otaku Mode(以下 TOM)ソフトウェアエンジニアの稲田です。

TOM では今まで検索エンジンとして Amazon CloudSearch を使ってきました。CloudSearch は自前でサーバーを管理することなく利用でき、手軽に検索エンジンを持つことができるため大変便利です。ですが、運用していくうちに TOM では 3 つの問題が出てきました。

  • CloudSearch を開発者ごとに用意できない
  • グローバルネットワーク経由なので遅い
  • 複数条件のファセットを 1 回で取得できない

これらの問題を解決するべく色々と検証を行い、新たな検索エンジンとして Elasticsearch を採用するに至りました。

CloudSearch の問題点

CloudSearch を開発者ごとに用意できない

TOM では開発者ごとに個別に開発環境を構築しているため CloudSearch のドメインを開発者全員分用意するというのは現実的ではありません。それゆえに CloudSearch を使っている部分の開発では本番環境にデプロイするまでまともに動作確認ができないという問題がありました。

グローバルネットワーク経由なので遅い

CloudSearch はグローバルネットワーク経由でしか使えないためレイテンシが問題になります。TOM の検索ページではユーザーが入力した検索キーワードをサーバー側に送り、そこからさらに CloudSearch に投げて検索していたためページのレスポンス速度が遅くなっていました。

複数条件のファセットを 1 回で取得できない

CloudSearch では複数条件のファセットを 1 回で取得できないためレイテンシとサーバーリソースの消費が問題になります。例えば値段、商品カテゴリー、商品のキャラクターなどの件数をそれぞれ上位 10 件ずつ出したい場合、CloudSearch では値段のファセットを取得するクエリ、商品カテゴリーのファセットを取得するクエリ、などと個別にクエリを送る必要があります。これはただでさえ遅いグローバルネットワーク経由での通信を複数回行うことになり、有限なサーバーリソースが無駄に消費されてしまいます。

Elasticsearch での解決

Elasticsearch は開発者ごとに用意できる

Elasticsearch は単体のサーバープログラムなので、開発者ごとのローカル環境で構築できます。これによって本番と同様の環境を整えることができるため動作確認が容易になります。実際に開発環境で Elasticsearch を起動するだけなら下記 4 行だけで良いというのも手軽です。

curl -L -O https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.3.3/elasticsearch-2.3.3.tar.gz
tar -xvf elasticsearch-2.3.3.tar.gz
cd elasticsearch-2.3.3/bin
./elasticsearch

ローカルネットワークで構築できる

Elasticsearch は前述の通り単体のサーバープログラムなので、自前でサーバーを用意すれば全てローカルネットワークで完結できます。グローバルネットワーク経由でのアクセスしかできない CloudSearch に比べて転送速度の面で有利です。実際に TOM では CloudSearch のときと比べてデータの転送速度が 3 倍ほど速くなりました。

複数条件で aggregation できる

Elasticsearch は複数の aggregation (CloudSearch でいうファセット) それぞれに条件を指定して結果を取得することができます。

{
  "query": {
    "bool": {
      "must": [{"range": {"point_rate.general.max": {"gte": 0.001 }}}]
    }
  },
  "aggs": {
    "all_global_prices": {
      "global": {},
      "aggs": {
        "all_prices": {
          "filter": {
            "bool": {"must": [{"term": {"discontinued": 0}}]}
          },
          "aggs": {
            "max_price": {
              "range": {
                "field": "max_price",
                "ranges": [{"to": 10}, {"from": 10, "to": 20}]
              }
            }
          }
        }
      }
    },
    "all_global_brand_ids": {
      "global": {},
      "aggs": {
        "all_brand_ids": {
          "filter": {
            "bool": {"must": [{"exists": {"field": "country_codes"}}]}
          },
          "aggs": {
            "brand_ids": {"terms": {"field": "brand_ids"}}
          }
        }
      }
    }
  }
}

上記のクエリは global aggregation を使っているので all_global_pricesall_global_brand_ids の結果は query.bool の条件は加味されません。これによって複数条件の aggregation を 1 つのクエリにまとめられるのでネットワーク I/O が 1 回で済み、結果としてパフォーマンスが良くなります。

Amazon Elasticsearch Service vs 自前ホスティング

CloudSearch を使っていた TOM での問題点は Elasticsearch を使うことで解決できることが分かりました。次に検討したのは Amazon Elasticsearch Service (以下 Amazon ES) を使うか、自前でサーバー上に Elasticsearch を導入して運用するか、です。

Amazon ES は CloudSearch と同じくフルマネージドサービスです。自前でサーバーを管理する必要がなく手軽に Elasticsearch を導入できますが、2016 年 6 月現在では CloudSearch と同じくグローバルネットワーク経由でしか使えません。また、バージョンも 1.5.2 と古いです。(執筆時点での最新 stable は 2.3.3)

TOM では自前でホスティングする方を選択しました。1 番の理由は Amazon ES での Elasticsearch のバージョンが古いことです。1.5.x と 2.x では微妙にクエリの書き方が異なっていたりして、今後発生するであろうアップデートに追従する手間が削減できるというのも理由の 1 つです。

自前でホスティングする際のデメリットの 1 つとして管理コストが上げられます。TOM では新しいバージョンの Elasticsearch が使えること、設定などの自由度が高いこと、ローカルネットワークで構築できることといったメリットがデメリットよりも大きいと判断しました。

まとめ

TOM が CloudSearch から Elasticsearch に乗り換えた理由を説明しました。TOM にとっては CloudSearch よりも Elasticsearch がより合っていましたが、そうでない場合も多いと思います。会社やプロジェクトに最適なものを選ぶ際にこの記事が参考になれば幸いです。