一貫したスコアリングの取得

Elasticsearchがシャードとレプリカで動作することは、良好なスコアリングを得る上での課題を追加します。

スコアは再現性がない

同じユーザーが同じリクエストを連続して2回実行し、ドキュメントが両方の回で同じ順序で返ってこない場合、これはかなり悪い体験ですよね?残念ながら、レプリカがある場合(index.number_of_replicasが0より大きい)には、これが発生する可能性があります。理由は、Elasticsearchがクエリが向かうべきシャードをラウンドロビン方式で選択するため、同じクエリを連続して実行すると、同じシャードの異なるコピーに向かう可能性が高いからです。

では、なぜこれが問題なのでしょうか?インデックス統計はスコアの重要な部分です。そして、これらのインデックス統計は、削除されたドキュメントのために同じシャードのコピー間で異なる場合があります。ご存知のように、ドキュメントが削除または更新されると、古いドキュメントはインデックスから即座に削除されるわけではなく、単に削除されたとしてマークされ、次回その古いドキュメントが属するセグメントがマージされるときにのみディスクから削除されます。しかし、実際的な理由から、これらの削除されたドキュメントはインデックス統計に考慮されます。したがって、プライマリシャードが多くの削除されたドキュメントを削除する大規模なマージを完了したばかりの場合、レプリカ(まだ多くの削除されたドキュメントを持っている)とは十分に異なるインデックス統計を持つ可能性があり、そのためスコアも異なる可能性があります。

この問題を回避するための推奨される方法は、ログインしているユーザーを識別する文字列(ユーザーIDやセッションIDなど)をプレファレンスとして使用することです。これにより、特定のユーザーのすべてのクエリが常に同じシャードにヒットすることが保証されるため、スコアはクエリ間でより一貫性を保ちます。

この回避策にはもう一つの利点があります:2つのドキュメントが同じスコアを持つ場合、デフォルトでは内部のLuceneドキュメントID(_idとは無関係)によってソートされます。しかし、これらのドキュメントIDは同じシャードのコピー間で異なる可能性があります。したがって、常に同じシャードにヒットすることで、同じスコアを持つドキュメントのより一貫した順序を得ることができます。

関連性が間違っているように見える

同じ内容の2つのドキュメントが異なるスコアを持っていることに気付いたり、完全一致が最初にランク付けされていない場合、問題はシャーディングに関連している可能性があります。デフォルトでは、Elasticsearchは各シャードが自分自身のスコアを生成する責任を持っています。しかし、インデックス統計はスコアに重要な寄与をするため、シャードが類似のインデックス統計を持っている場合にのみ、これがうまく機能します。前提は、ドキュメントがデフォルトで均等にシャードにルーティングされるため、インデックス統計は非常に類似しており、スコアリングが期待通りに機能するというものです。しかし、次のいずれかの状況が発生した場合:

  • インデックス時にルーティングを使用する、
  • 複数のインデックスをクエリする、
  • またはインデックス内のデータが少なすぎる

その場合、検索リクエストに関与するすべてのシャードが類似のインデックス統計を持たない可能性が高く、関連性が悪くなる可能性があります。

小さなデータセットを持っている場合、この問題を回避する最も簡単な方法は、すべてを単一のシャード(index.number_of_shards: 1)を持つインデックスにインデックスすることです。これがデフォルトです。そうすれば、すべてのドキュメントのインデックス統計は同じになり、スコアは一貫性を保ちます。

そうでない場合、この問題を回避するための推奨される方法は、dfs_query_then_fetch検索タイプを使用することです。これにより、Elasticsearchは関与するすべてのシャードに初期のラウンドトリップを行い、クエリに関連するインデックス統計を尋ね、その後、コーディネーティングノードがそれらの統計をマージし、シャードにqueryフェーズを実行するように要求する際にマージされた統計をリクエストと共に送信します。これにより、シャードはスコアリングを行うために自分自身の統計ではなく、これらのグローバル統計を使用できます。

ほとんどの場合、この追加のラウンドトリップは非常に安価であるべきです。しかし、クエリに非常に多くのフィールド/用語やファジークエリが含まれている場合、統計を収集するだけでも安価ではない可能性があるため、すべての用語が統計を調べるために用語辞書で検索される必要があります。