Elasticsearchのマッピング設定最適化によるインデキシングパフォーマンス改善への取り組み

header

こんにちは。EC基盤本部 検索基盤部 検索基盤チームの有村(@paki0o)です。

みなさん、Elasticsearchのマッピングはどこまで厳密に管理されているでしょうか。

弊社では以前のテックブログでご紹介した通り、一部を除きExplicit Mappingにてデータを管理しています。

techblog.zozo.com

設定している項目は、フィールド名・タイプ・適用するアナライザなど一般的な項目であり、詳細まで詰め切れているとは言い切れない状況でした。今回、マッピング設定の変更がパフォーマンスに与える影響を検証しましたので、その内容についてご紹介いたします。

背景と課題

ZOZOTOWNの商品情報インデックスは数百万件のドキュメント、100以上のフィールドから構成されています。その中には、おすすめ順で並び替えるためのアイテム特徴量情報や人気順情報を表すフィールドなど、特定の用途でのみ利用するフィールドも含まれています。

またオペレーションの面では、週次で全件洗い替えを行うバッチや数時間毎に人気順情報を更新するバッチ、アイテム特徴量情報を更新するバッチなど、大規模な更新がかなり多いシステムとなっています。

ElasticsearchはUpdateクエリによるパーシャルアップデートをサポートしており、先のアイテム特徴量更新バッチでも利用しています。ただ、パーシャルアップデートはドキュメントにもある通り、更新されたドキュメント全体のリインデキシングが走ります。人気順更新バッチやアイテム特徴量更新バッチは、全商品データをパーシャルアップデートするため、弊社のシステムは1日に複数回も全件洗い替えと同等の負荷がかかっている状況となっています。

また、ビジネス要件の実現や様々な検索改善への取り組みの一環で、日々新規のフィールドを追加しており今後も継続すると考えられます。現に今年度の頭には、これまで100項目ほどであったフィールド数を、150項目ほどまで増やす改修がありました。このようなフィールド数増加によるインデキシングパフォーマンスの低下は大きな課題です。今後も同規模の改修が検討されており、設定レベルでインデキシングを効率化できないか検証しました。

マッピングの設定について

Elasticsearchのマッピングでは、フィールドごとに指定できるパラメータがバージョン7.13時点で27項目存在しています。

www.elastic.co

今回は、この中でもデータをどのように扱うかを指定する以下の3つのパラメータを設定し、パフォーマンスにどのような影響があるか検証しました。

  • index
  • doc_values
  • enabled

index

indexは文字通り、該当のフィールドをインデキシングさせるかを指定するためのパラメータです。インデキシングを無効化したフィールドは検索対象への指定ができなくなるため、検索が不要なフィールドに設定します。デフォルトはtrueで、明示的にfalseを指定することで、インデキシングを無効化できます。

設定例は以下の通りです。

PUT /sample_index
{
  "mappings": {
    "properties": {
      "sample_field": {
        "type": "integer",  
        "index": false
      }
    }
  }
}

doc_values

doc_valuesは各フィールドのdoc_valuesを保存するかを指定するパラメータです。doc_valuesはソートや集計クエリ、scriptクエリなどフィールド単位の処理が必要とされる際に利用される列指向なデータです。デフォルトはtrueで、明示的にfalseを指定することで、doc_values形式での保存を無効化できます。

設定例は以下の通りです。

PUT /sample_index
{
  "mappings": {
    "properties": {
      "sample_field": {
        "type": "integer",  
        "doc_values": false
      }
    }
  }
}

enabled

enabledは入力されたデータを有効化するかを指定するパラメータです。これを無効にすると、インデキシングやその他の形式を含めてデータがストアされません。検索やソートなどの対象として一切利用できなくなりますが、例えばタイムスタンプやUUIDのような_sourceで確認さえできれば問題ないフィールドに対しては有効な設定です。デフォルトはtrueで、明示的にfalseを指定することで、フィールド全体を無効化できます。

注意点として、enabledfalseに設定する際には、フィールドの型をObject型に指定する必要があります。

設定例は以下の通りです。

PUT /sample_index
{
  "mappings": {
    "properties": {
      "sample_field": {
        "type": "object",  
        "enabled": false
      }
    }
  }
}

3項目の比較

ここまで紹介した3項目について、それぞれ単体で指定した際にどのような用途でフィールドが利用できるのか・できないのかを以下の表でまとめました。

用途 index=false doc_values=false enabled=false
検索 × ×
script × ×
ソート × ×
集計 × ×
_source

弊社でもソート・scriptだけに用いるフィールド、検索だけに利用できれば問題ないフィールドなど、その用途ごとに最適化の余地がありました。必要最低限の項目のみを設定し、どの程度インデキシング処理が変わるのか検証しました。

検証

前準備

各フィールドごとに適切なパラメータを設定する前準備として、現状の各フィールドと用途を洗い出し、必要な項目を整理しました。単純にクエリログから抽出可能であればスクリプトで処理可能でしたが、プラグインなどの諸事情によりクエリログからすべての情報を得ることが難しかったため、スプレッドシートにまとめる形を取りました。

Elasticsearchのフィールドと用途一覧

まとめた結果、現状と理想形の設定差分は以下の通りとなりました。カッコ内の数字はそれぞれ全体のうちの割合を示しています。

項目 検証前の設定数 検証後の設定数 変化分
フィールド数 159 159 -
index=false 65(40.8%) 79(49.6%) +14 (+8.8%)
doc_values=false 5(3.1%) 55(34.6%) +50 (+31.5%)
enabled=false 4(2.5%) 14(8.8%) +14 (+6.3%)

比較項目

変更前後のパフォーマンス計測はElasticsearchのMonitoring機能を用いて行いました。Monitoring機能で取れるメトリクスは非常に豊富なため、今回はその中からインデキシング関連のメトリクスに対象を絞り、以下の項目について比較検証を行いました。

項目名 内容
store.size_in_bytes インデックスサイズ (byte)
segments.count セグメント数
segments.index_writer_memory_in_bytes Index Writerの使用メモリ (byte)
indexing.index_time_in_millis / indexing.index_total インデキシング速度 (ms/document)

なお取得タイミングによって値に差が出るため、それぞれ変更を適用する前後、同曜日の1日の平均値で比較しました。またECサイトの特性上、イベント事やセールなどの要因によりリクエストの傾向が異なるため、平日と休日からそれぞれ1日ずつ比較しています。

検索速度についても同様に計測を試みましたが、対象期間に検索クエリを変更するABテストを実施しており、正確な計測が難しいとの判断から今回は対象外としています。

検証結果

検証結果は以下の表の通りです。表中の「インデックスサイズ」と「Index Writerの使用メモリ」は、見やすいように単位を調整しています。

平日での比較結果

項目 適用前(平日) 適用後(平日) 変化分
インデックスサイズ (GB) 15.327 14.788 -3.5%
セグメント数 37.862 35.764 -5.5%
Index Writerの使用メモリ (MB) 48.106 44.199 -8.1%
インデキシング速度 (ms/document) 1.210 1.138 -5.9%

休日での比較結果

項目 適用前(休日) 適用後(休日) 変化分
インデックスサイズ (GB) 15.650 14.773 -5.6%
セグメント数 37.250 35.339 -5.1%
Index Writerの使用メモリ (MB) 51.367 42.370 -17.5%
インデキシング速度 (ms/document) 1.120 1.082 -3.4%

考察

今回計測したすべてのメトリクスにおいて改善している状態が確認できました。特に、Index Writerの使用メモリは変更を加えたフィールド数の割合と近い値で減少しており、適切な設定の重要さが伺えます。

一方で、今回の改修により一部フィールドが検索、もしくはソートや集計に利用できなくなったのも事実です。設定を戻し、インデキシングし直すことで再度有効化も可能ですが、データサイズによっては即座にできるものではありません。このあたり小回りを優先するかパフォーマンスを優先するかは要件に依存する部分かとは思いますが、弊チームではパフォーマンスを優先し、今回の改修を採用しました。

まとめ

本記事では、Elasticsearchへの継続的なフィールド数追加の要望に対応するため、設定の深堀りと見直しを行いました。取り組みの結果、パラメータを用途に応じて最適化することでインデックスのサイズやクラスタへの負荷、インデキシングにかかる時間を低減できることがわかりました。

今回は検索を主な用途とするクラスタで検証しましたが、例えばロギング用途のようなログの閲覧と集約さえできれば問題ないようなユースケースでは更に改善も期待できると思いますので、是非お試しください。

最後に、ZOZOテクノロジーズでは、検索機能を開発・改善していきたいエンジニアを全国から募集中です。ご興味のある方は、以下のリンクからぜひご応募ください!

hrmos.co

カテゴリー