Elasticsearchの検索クエリの遅延診断と修正

Elasticsearchの検索速度の遅さに悩んでいませんか?この包括的なガイドは、非効率的なクエリ、マッピングの問題、ハードウェアの制限など、一般的なパフォーマンスのボトルネックを特定するのに役立ちます。Elasticsearchの組み込みツールを使用して遅いクエリを診断し、より高速で応答性の高い検索結果を実現するための実践的なソリューションを実装する方法を学びましょう。実践的なヒントとベストプラクティスで、クラスターを最高のパフォーマンスに最適化してください。

Elasticsearchの検索クエリが遅い場合の診断と修正方法

Elasticsearchの検索が遅くなる原因は、通常、広範なクエリ、負荷の高い集計、マッピングの選択、シャードのレイアウト、またはクラスターへのリソース負荷にあります。インデックスが成長した後に検索APIがタイムアウトしたり、レイテンシが急上昇したりした場合は、クエリ、インデックス、クラスターのいずれが過剰な処理を行っているかを特定する必要があります。

スローログとプロファイルAPIを使用して負荷の高い部分を特定し、その証拠に基づいてクエリ、マッピング、シャード戦略、またはハードウェアを調整します。

Elasticsearchの検索が遅くなる一般的な原因

検索クエリのパフォーマンス低下にはいくつかの要因が考えられます。効果的なトラブルシューティングには、環境における具体的な原因を特定することが重要です。

1. 非効率なクエリ

クエリの設計は、検索パフォーマンスに最も直接的な影響を与えることがよくあります。複雑または構造が不適切なクエリは、Elasticsearchに多くの処理を強いることになり、レイテンシの増加につながります。

  • 広範なクエリ: 十分なフィルタリングを行わずに大量のドキュメントやフィールドをスキャンするクエリ。
    • 例: 大規模なインデックスに対するmatch_allクエリ。
  • 深いページネーション: fromsizeを使用して非常に大きなページを要求すること。ユーザー向けの深いページネーションには、安定したソートとポイントインタイム検索を備えたsearch_afterを推奨します。スクロールは主にバッチ処理やreindexスタイルのワークロードに使用します。
  • 複雑な集計: 過度に複雑またはリソースを大量に消費する集計。特に広範なクエリと組み合わせた場合。
  • ワイルドカードクエリ: 先頭のワイルドカード(例:*term)は特に非効率的で、転置インデックスのルックアップを効果的に使用できません。末尾のワイルドカードは一般的に優れていますが、大規模なデータセットでは遅くなる可能性があります。
  • 正規表現クエリ: 計算コストが高くなる可能性があるため、控えめに使用する必要があります。

2. マッピングの問題

データのインデックス方法(マッピングで定義)は、検索速度に大きな影響を与えます。誤ったマッピングの選択は、非効率なインデックス作成と検索の低速化につながる可能性があります。

  • 動的マッピング: 便利ですが、動的マッピングは予期しないフィールドタイプや不要なanalyzedフィールドの作成につながり、インデックスサイズと検索オーバーヘッドを増加させる可能性があります。
  • textフィールドとkeywordフィールド: 完全一致やソート/集計にtextフィールドを使用する場合、keywordフィールドの方が適切です。textフィールドは全文検索用に分析され、keywordフィールドはそのままインデックスされるため、完全一致、ソート、集計に最適です。
    • 例: 製品ID(PROD-123)でフィルタリングする必要がある場合、textではなくkeywordとしてマッピングする必要があります。
    PUT my-index
    {
      "mappings": {
        "properties": {
          "product_id": {
            "type": "keyword"
          }
        }
      }
    }
    
  • 古い_allフィールドの想定: 古いバージョンのElasticsearchには、他のフィールドのコンテンツをインデックスする_allフィールドがありました。最新バージョンでは削除されたため、結合された検索テキストが必要な場合は、明示的なフィールドまたはcopy_toを使用します。
  • ネストされたデータ構造: nestedデータ型はリレーションシップを維持するのに強力ですが、注意深くクエリしないと、flattenedobject型と比較してクエリのリソース消費が大きくなる可能性があります。

3. ハードウェアとクラスターの設定

基盤となるインフラストラクチャとElasticsearchの設定方法は、パフォーマンスに重要な役割を果たします。

  • 不十分なハードウェアリソース:
    • CPU: CPU使用率が高いと、非効率なクエリや大量のインデックス作成/検索負荷を示している可能性があります。
    • RAM: RAMが不十分だと、オペレーティングシステムがメモリをスワップするため、ディスクI/Oが増加します。ElasticsearchはJVMヒープとOSファイルシステムキャッシュにも大きく依存しています。
    • ディスクI/O: 低速なディスク(特にHDD)は大きなボトルネックになります。本番環境のElasticsearchクラスターにはSSDの使用を強く推奨します。
  • シャードのサイズと数:
    • 多すぎる小さなシャード: 各シャードにはオーバーヘッドがあります。非常に多くの小さなシャードはクラスターを圧倒する可能性があります。
    • 少なすぎる大きなシャード: 大きなシャードはリカバリ時間が長くなり、負荷の分散が不均一になる可能性があります。
    • 一般的なガイドライン: 数十ギガバイトのシャードは、多くのログおよび検索ワークロードで一般的ですが、適切なサイズはデータ量、クエリパターン、リカバリ目標、ノードリソースによって異なります。
  • レプリカ: レプリカは可用性と読み取りスループットを向上させますが、インデックス作成のオーバーヘッドとディスク容量の使用量も増加させます。レプリカが多すぎるとリソースに負荷がかかる可能性があります。
  • JVMヒープサイズ: JVMヒープが適切に設定されていないと、ガベージコレクションの一時停止が発生する可能性があります。一般的な開始点はシステムRAMの半分以下で、オペレーティングシステムのファイルキャッシュに十分なメモリを残すことです。お使いのElasticsearchバージョンのヒープガイダンスに従ってください。
  • ネットワークレイテンシ: 分散環境では、ノード間のネットワークレイテンシがノード間通信と検索調整に影響を与える可能性があります。

4. 検索に影響を与えるインデックス作成パフォーマンスの問題

この記事は検索に焦点を当てていますが、インデックス作成中の問題が間接的に検索速度に影響を与える可能性があります。

  • 高いインデックス作成負荷: クラスターがインデックス要求に追いつくのに苦労している場合、検索パフォーマンスに影響を与える可能性があります。これは多くの場合、不十分なハードウェアまたは最適化されていないインデックス作成戦略が原因です。
  • 多数のセグメント: 定期的なセグメントマージを行わずに頻繁にインデックス作成を行うと、多数の小さなセグメントが発生する可能性があります。Elasticsearchはセグメントを自動的にマージしますが、このプロセスはリソースを大量に消費し、一時的に検索を遅くする可能性があります。

遅いクエリの診断

修正を実装する前に、どのクエリが遅いのか、その理由を特定する必要があります。

1. Elasticsearchスローログ

Elasticsearchを設定して遅いクエリをログに記録します。これは問題のある検索リクエストを特定する最も直接的な方法です。

  • 設定: インデックスごとにスローログのしきい値を設定します。Elasticsearchが期待するログレベルサフィックス(warninfodebugtraceなど)を使用します。
    PUT _settings
    {
      "index": {
        "search": {
          "slowlog": {
            "threshold": {
              "query": {
                "warn": "1s"
              },
              "fetch": {
                "warn": "1s"
              }
            }
          }
        }
      }
    }
    
    • query: クエリフェーズの実行に指定されたしきい値より長くかかるクエリをログに記録します。
    • fetch: フェッチフェーズ(実際のドキュメントの取得)の実行に指定されたしきい値より長くかかるクエリをログに記録します。
  • ログの場所: スローログはElasticsearchのログを通じて書き込まれ、パッケージ、デプロイプラットフォーム、ログ設定に応じて、別の検索スローログファイルに表示されることがよくあります。

2. Elasticsearchモニタリングツール

モニタリングツールを活用して、クラスターの健全性とパフォーマンスに関する洞察を得ます。

  • Elastic Stackモニタリング: 設定すると、CPU、メモリ、ディスクI/O、JVMヒープ使用量、クエリレイテンシ、インデックス作成レートなどのダッシュボードを提供します。
  • APM(アプリケーションパフォーマンスモニタリング): アプリケーションからElasticsearchへのリクエストをトレースし、アプリケーションまたはElasticsearchレベルのボトルネックを特定するのに役立ちます。
  • サードパーティツール: 高度なモニタリングおよび分析機能を提供する外部ツールが多数あります。

3. 分析API

_analyze APIは、テキストフィールドがどのようにトークン化および処理されるかを理解するのに役立ち、全文検索の問題のデバッグに不可欠です。

  • 例: クエリ文字列がどのように処理されるかを確認します。
    GET my-index/_analyze
    {
      "field": "my_text_field",
      "text": "Quick brown fox"
    }
    

4. プロファイルAPI

非常に具体的なクエリパフォーマンスチューニングのために、プロファイルAPIは検索リクエストの各コンポーネントの詳細なタイミング情報を提供できます。

  • 例:
    GET my-index/_search
    {
      "profile": true,
      "query": {
        "match": {
          "my_field": "search term"
        }
      }
    }
    

遅いクエリの修正:解決策と最適化

根本原因を特定したら、的を絞った解決策を実装できます。

1. クエリの最適化

  • フィルターコンテキスト: スコアリングが不要な条件にはfilter句を使用します。Elasticsearchはこれらをyes/noフィルターとして実行し、頻繁に使用されるフィルターをキャッシュする可能性があります。
    GET my-index/_search
    {
      "query": {
        "bool": {
          "must": [
            { "match": { "title": "elasticsearch" } }
          ],
          "filter": [
            { "term": { "status": "published" } },
            { "range": { "publish_date": { "gte": "now-1M/M" } } }
          ]
        }
      }
    }
    
  • 先頭ワイルドカードを避ける: 可能であれば、先頭ワイルドカード(*term)を避けるようにクエリを書き換えます。ngramトークナイザーや代替の検索方法の使用を検討してください。
  • フィールドスキャンを制限する: クエリとレスポンスの_sourceフィルタリングで必要なフィールドのみを指定します。
  • 深いページネーションにはsearch_afterを使用する: 浅いページを超えるインタラクティブなページネーションには、決定論的なソートとともにsearch_afterを使用します。大規模なエクスポートには、Elasticsearchのバージョンとワークロードに応じて、スクロールまたはポイントインタイムとsearch_afterを使用します。
  • 集計を簡素化する: 複雑な集計を見直して最適化します。集計の深いページネーションにはcomposite集計の使用を検討してください。
  • 完全一致/ソートにはkeyword: 完全一致、ソート、または集計に使用されるフィールドはkeywordとしてマッピングされていることを確認します。

2. マッピングの改善

  • 明示的なマッピング: 動的マッピングのみに依存するのではなく、インデックスに明示的なマッピングを定義します。これにより、フィールドが正しいタイプでインデックスされることが保証されます。
  • _sourcedoc_valuesに注意する: _sourceを無効にすると、更新、reindex、ハイライト表示、デバッグワークフローが壊れる可能性があります。ソートや集計に使用されるフィールドでdoc_valuesを無効にすると、それらのワークロードに悪影響を及ぼします。これらはデフォルトの検索修正ではなく、ストレージの最適化として扱います。
  • index_options: textフィールドの場合、index_optionsを微調整して必要な情報のみを保存します(例:フレーズクエリのポジション)。

3. ハードウェアとクラスターのチューニング

  • ハードウェアのアップグレード: より高速なCPU、より多くのRAM、特にSSDに投資します。
  • シャーディング戦略の最適化: シャードの数とサイズを見直します。必要に応じて、最適化されたシャーディング戦略で新しいインデックスにデータをreindexすることを検討してください。インデックスライフサイクル管理(ILM)などのツールを使用して、時間ベースのインデックスとそのシャーディングを管理します。
  • JVMヒープの調整: JVMヒープが正しくサイズ設定されていること(例:RAMの50%、最大30〜32GB)を確認し、ガベージコレクションを監視します。
  • ノードロール: リソースの競合を防ぐために、ロール(マスター、データ、インジェスト、コーディネート)を異なるノードに分散します。
  • レプリカの増加(読み取り負荷の高いワークロードの場合): ボトルネックが読み取りスループットであり、インデックス作成ではない場合は、レプリカの追加を検討しますが、インデックス作成への影響を監視します。

4. インデックスの最適化

  • フォースマージ: 読み取り専用のインデックスでのみ_forcemergeを実行します。これにより、セグメントが減り、検索とストレージが改善されます。これはリソースを大量に消費し、インデックスが書き込みを受け続けている場合に書き換えにコストがかかる非常に大きなセグメントを作成する可能性があります。
    POST my-index/_forcemerge?max_num_segments=1
    
  • インデックスライフサイクル管理(ILM): ILMを使用してインデックスを自動的に管理します。これには、古い非アクティブなインデックスに対するフォースマージなどの最適化フェーズが含まれます。

パフォーマンスを維持するためのベストプラクティス

  • 定期的に監視する: 継続的な監視は、パフォーマンスの低下を早期に発見するための鍵です。
  • 変更をテストする: 本番環境に重要な変更をデプロイする前に、ステージング環境でテストします。
  • データとクエリを理解する: 最適な最適化は状況に応じて異なります。どのようなデータがあり、どのようにクエリするかを把握します。
  • Elasticsearchを最新の状態に保つ: 新しいバージョンには、パフォーマンスの改善やバグ修正が含まれていることがよくあります。
  • クラスターのサイズを適切に設定する: リソースの過剰プロビジョニングまたは過小プロビジョニングを避けます。定期的にクラスターのニーズを評価します。

まとめ

Elasticsearchの検索が遅い問題を修正するには、まず測定を行います。スローログはどのリクエストが問題かを示し、プロファイルAPIは時間がどこで費やされているかを示し、クラスターメトリクスはクエリがヒーププレッシャー、ディスクI/O、インデックス作成、またはシャードオーバーヘッドと競合しているかどうかを示します。1つの変更を行い、同じクエリを再実行し、レイテンシとリソース使用量が改善された場合のみ結果を保持します。