キャッシュとクエリウォーミング

Solr のキャッシュは、クエリのパフォーマンスを向上させるための重要な方法を提供します。キャッシュは、ドキュメント、クエリで使用されるフィルター、および以前のクエリの結果を格納できます。

キャッシュはコミット後にクリアされ、通常、そのメリットを再び確認するには、再読み込みが必要です。これを回避するために、新しい検索子がオープンされると見なされる前に、古いキャッシュからの値で新しいキャッシュを自動的に設定することにより、キャッシュを「ウォーミング」できます。

キャッシュ管理は、Solr の実装を成功させるために不可欠であるため、アプリケーションの成長に合わせてキャッシュを微調整する必要があることに注意する必要があります。

solrconfig.xml 内の <query>

このセクションの設定は、Solr がクエリを処理して応答する方法に影響を与えます。

これらの設定はすべて、solrconfig.xml<query> 要素の子要素で構成されます。

<config>
  <query>
    ...
  </query>
</config>

キャッシュ

Solr キャッシュは、インデックス検索子の特定のインスタンス、つまり、検索子のライフサイクル中に変化しないインデックスの特定のビューに関連付けられています。そのインデックス検索子が使用されている限り、そのキャッシュ内のアイテムは有効であり、再利用できます。デフォルトでは、キャッシュされた Solr オブジェクトは一定時間経過後に期限切れになることはありません。代わりに、インデックス検索子のライフサイクル中は有効なままです。アイドル時間に基づく期限切れは、maxIdleTime オプションを使用することで有効にできます。

新しい検索子がオープンされると、現在の検索子は、新しい検索子がキャッシュを自動ウォーミングしている間、リクエストの処理を続行します。新しい検索子は、現在の検索子のキャッシュを使用して、自身のキャッシュを事前に設定します。新しい検索子の準備が整うと、現在の検索子として登録され、すべての新しい検索リクエストの処理を開始します。古い検索子は、すべてのリクエストの処理が完了すると閉じられます。

キャッシュの実装

Solr には、さまざまなタイプのキャッシュに使用されるデフォルトの SolrCache 実装が付属しています。

CaffeineCache は、Caffeine キャッシュライブラリによってバックアップされた実装です。デフォルトでは、Window TinyLFU (W-TinyLFU) エビクションポリシーを使用します。これにより、小さなフットプリントで O(1) 時間で、使用頻度と使用頻度の両方に基づいてエビクションを行うことができます。通常、このキャッシュは、従来のキャッシュよりも低いメモリフットプリント、より高いヒット率、およびより優れたマルチスレッドパフォーマンスを提供します。

CaffeineCache は、ウォーミングが発生したときにキャッシュの現在のサイズを基準に評価される整数とパーセンテージの両方をサポートする自動ウォーミングカウントを使用します。

Solr Admin UI のプラグインと統計画面には、アクティブなすべてのキャッシュのパフォーマンスに関する情報が表示されます。この情報は、特定のアプリケーションに合わせてさまざまなキャッシュのサイズを適切に微調整するのに役立ちます。検索子が終了すると、そのキャッシュの使用状況の概要もログに書き込まれます。

キャッシュパラメータ

各キャッシュには、初期サイズ (initialSize)、最大サイズ (size)、およびウォーミング中に使用するアイテム数 (autowarmCount) を定義するための設定があります。autowarmCount の場合、絶対値の代わりにパーセンテージで表現することもできます。

maxIdleTime 属性は、しばらく使用されていないエントリの自動エビクションを制御します。この属性は秒単位で表され、デフォルト値の 0 は、アイドル時間が超過したためにエントリが自動的にエビクションされないことを意味します。この属性の値を小さくすると、古いエントリがすぐにエビクションされ、キャッシュメモリの使用量は減少しますが、代わりに同じエントリの繰り返しエビクション-ルックアップ-ミス-挿入サイクルによりスラッシングが発生する可能性があります。値を大きくすると、エントリが再利用されるのを待って長く留まり、メモリ使用量が増加します。クエリのボリュームとパターンに応じて、適切な値は 60〜3600 の間にあります。

maxRamMB 属性は、キャッシュが消費できるメモリの最大量を制限します。sizemaxRamMB の両方の制限が指定されている場合、maxRamMB の制限が優先され、size の制限は無視されます。

async 属性は、キャッシュが直接的な結果を格納するのか (async=false、無効)、それとも計算への間接的な参照を格納するのか (async=true、デフォルトで有効) を決定します。クエリに子ドキュメントや結合クエリが含まれる場合、async キャッシュが正常に機能するために有効にする必要があります。async オプションを無効にすると、CPU 使用率が増加する代わりに、キャッシュエントリあたりのメモリ使用量がわずかに減少する可能性があります。async キャッシュは、まだキャッシュされていない同じ結果セットを要求する多数の同時実行クエリで最も大幅な改善を提供し、キャッシュサイズを大きくしたり、自動ウォーミングの数を増やしたりする代替手段となります。ただし、async キャッシュは、時間制限付きのクエリに対するデータ競合を防ぐことはありません。これは、それらが部分的な結果を提供すると予想されるためです。

すべてのキャッシュは、パラメータ enabledfalse の値を指定して無効にすることができます。キャッシュは、「cache ローカルパラメータ」のセクションで説明されているように、cache パラメータを使用してクエリごとに無効にすることもできます。

各キャッシュの詳細は以下で説明します。

フィルターキャッシュ

このキャッシュは、解析されたクエリとそれに一致するすべてのドキュメントの順序なしのセットをペアで保持します。そのようなセットが明らかに小さい場合を除き、セットの実装はビットセットです。

Solr が filterCache を使用する最も一般的な方法は、各 fq 検索パラメータの結果をキャッシュすることですが、他にもいくつかのケースがあります。同じパラメータフィルタクエリを使用する後続のクエリでは、キャッシュヒットが発生し、結果が迅速に返されます。fq の詳細については、「fq (フィルタークエリ) パラメータ」を参照してください。このキャッシュの使用は、「cache ローカルパラメータ」を使用して fq に対して無効にすることができます。

このキャッシュを使用する別の Solr 機能は、デフォルトの Lucene クエリパーサーの filter(…​) 構文です。

Solr は、構成パラメータ facet.methodfc に設定されている場合、ファセット処理にもこのキャッシュを使用します。ファセットパラメータの詳細については、「フィールド値ファセットパラメータ」を参照してください。

<filterCache class="solr.CaffeineCache"
             size="512"
             initialSize="512"
             autowarmCount="128"/>

キャッシュは、このキャッシュで使用されるヒープの最大量を制限する maxRamMB パラメータをサポートしています。CaffeineCache は、ヒープ使用量またはサイズのいずれかによる削除のみをサポートしていますが、両方はサポートしていません。したがって、maxRamMB が指定されている場合、size パラメータは無視されます。

<filterCache class="solr.CaffeineCache"
             maxRamMB="1000"
             autowarmCount="128"/>

フィルターキャッシュは、async 計算を有効にするのに適した候補です。

<filterCache class="solr.CaffeineCache"
             size="1024"
             autowarmCount="0"
             async="true"/>

クエリ結果キャッシュ

queryResultCache は、以前の検索の結果を保持します。これは、クエリ、ソート、および要求されたドキュメントの範囲に基づいて順序付けられたドキュメント ID (DocList) のリストです。

queryResultCache には、使用される RAM の最大量 (maxRamMB) を制限するオプション設定があります。これにより、このキャッシュの内容が使用するヒープサイズをメガバイト単位で指定できます。キャッシュがこのサイズを超えて大きくなると、キャッシュのヒープ使用量が指定された制限を下回るまで、最も古いアクセス済みのクエリが削除されます。maxRamMB に加えて size が指定されている場合、ヒープ使用量の制限のみが適用されます。

このキャッシュの使用は、q で「cache ローカルパラメータ」を使用してクエリごとに無効にすることができます。

<queryResultCache class="solr.CaffeineCache"
                  size="512"
                  initialSize="512"
                  autowarmCount="128"/>

ドキュメントキャッシュ

documentCache は、Lucene の Document オブジェクト (各ドキュメントの格納されたフィールド) を保持します。Lucene の内部ドキュメント ID は一時的なものであるため、このキャッシュは自動ウォーミングされません。

documentCache のサイズは、Solr がリクエスト中にドキュメントを再取得する必要がないように、常に max_resultsmax_concurrent_queries を乗算した値より大きくする必要があります。ドキュメントに格納するフィールドが多いほど、このキャッシュのメモリ使用量が高くなります。

<documentCache class="solr.CaffeineCache"
               size="512"
               initialSize="512"
               autowarmCount="0"/>

ユーザー定義キャッシュ

独自のアプリケーションコードで使用するための名前付きキャッシュを定義することもできます。SolrIndexSearcher メソッド getCache()cacheLookup()、および cacheInsert() を呼び出すことで、名前でキャッシュオブジェクトを見つけて使用できます。

<cache name="myUserCache" class="solr.CaffeineCache"
                          size="4096"
                          initialSize="1024"
                          autowarmCount="1024"
                          regenerator="org.mycompany.mypackage.MyRegenerator" />

キャッシュの自動ウォーミングが必要な場合は、solr.search.CacheRegenerator を実装するクラスの完全修飾名を持つ regenerator 属性を含めます。NoOpRegenerator を使用することもできます。これは、古い項目でキャッシュを再設定するだけです。regenerator パラメータで regenerator="solr.NoOpRegenerator" として定義します。

キャッシュサイズと使用状況の監視

キャッシュ統計」のセクションでは、各キャッシュで使用できるメトリックについて説明します。メトリックには、「プラグインと統計画面」または「メトリクス API」でアクセスできます。

キャッシュを評価する際に確認する最も重要なメトリックは、サイズとヒット率です。

サイズは、キャッシュ内の項目の数を示します。一部のキャッシュは、RAM の最大キャッシュサイズを MB 単位で設定することをサポートしています。

ヒット率は、キャッシュによって処理されたクエリの割合であり、0 から 1 の間の数値で示されます。値が高いほど、キャッシュが頻繁に使用されていることを示し、値が低いほど、キャッシュがクエリにあまり役立っていないことを示します。理想的には、この数は 1 にできるだけ近い必要があります。

ヒット率が低いがキャッシュサイズを高く設定している場合は、キャッシュサイズを小さくすることで最適化できます。使用されていないオブジェクトをメモリに保持する必要はありません。

もう 1 つの便利なメトリックは、キャッシュから削除されたオブジェクトを測定するキャッシュ削除です。削除率が高い場合は、キャッシュが小さすぎる可能性があり、それを増やすとヒット率が向上する可能性があります。あるいは、ヒット率が高いが削除が少ない場合は、キャッシュが大きすぎる可能性があり、サイズを小さくすることでメリットが得られる可能性があります。

ヒット率が低いことは、常に特定のキャッシュの問題を示すものではありません。クエリが頻繁に繰り返されない場合は、キャッシュされたオブジェクトが再利用される可能性が低いため、ヒット率が低いことが予想されます。このような場合は、システムに小さいキャッシュサイズが最適である可能性があります。

クエリのサイズ設定とウォーミング

クエリのサイズとキャッシュをウォーミングする方法を制御するために、いくつかの要素が用意されています。

<maxBooleanClauses> 要素

ブールクエリ文字列を解析するときに許可される句の最大数を設定します。

この制限は、ユーザーがクエリ文字列の一部として指定したブールクエリにのみ影響し、ユーザーが指定したブールクエリがどの程度複雑になるかをコレクションごとに制御します。これよりも多くの句を指定するクエリ文字列はエラーになります。

このコレクションごとの制限が、solr.xml で指定されている「グローバル maxBooleanClauses 制限」よりも大きい場合、その設定もユーザーが指定したブールクエリのサイズを制限するため、効果はありません。

デフォルト構成では、このプロパティは指定されている場合、solr.max.booleanClauses システムプロパティの値を使用します。これは、デフォルトの solr.xml の「グローバル maxBooleanClauses 設定」で使用されるのと同じシステムプロパティであるため、Solr 管理者は、各コレクションの solrconfig.xml ファイルを検索して更新する必要なく、両方の値 (すべてのコレクションで) を簡単に増やすことができます。

<maxBooleanClauses>${solr.max.booleanClauses:1024}</maxBooleanClauses>

<enableLazyFieldLoading> 要素

このパラメータが true に設定されている場合、直接要求されないフィールドは、必要に応じてのみロードされます。

最も一般的なクエリがフィールドの小さなサブセットのみを必要とする場合、特にアクセス頻度の低いフィールドのサイズが大きい場合、これによりパフォーマンスを向上させることができます。

<enableLazyFieldLoading>true</enableLazyFieldLoading>

<useFilterForSortedQuery> 要素

この設定は、要求されたソートに「score」が含まれていないクエリ (またはスコアが関連しないクエリ - たとえば、ドキュメントが要求されていない、クエリが定数スコアを出力する) にのみ影響します。このような場合、この要素を true に構成すると、メインクエリに一致するフィルターに対して filterCache が参照されます。これは、同じ検索が、offset または cursorMark を介して異なるソートオプションまたは異なるページネーションで繰り返し発行される場合に役立ちます (繰り返しますが、「score」がソートに含まれていないか、要求されたソートに関連しない場合に限ります)。このオプションを有効にする場合は、filterCache に予想される使用パターンをサポートするのに十分な容量があることを確認してください。

<useFilterForSortedQuery>true</useFilterForSortedQuery>

<queryResultWindowSize> 要素

queryResultCache と一緒に使用すると、要求されたドキュメント ID のスーパーセットがキャッシュされます。

たとえば、クエリがドキュメント 10 から 19 を要求し、queryWindowSize が 50 の場合、ドキュメント 0 から 49 がキャッシュされます。

<queryResultWindowSize>20</queryResultWindowSize>

<queryResultMaxDocsCached> 要素

このパラメータは、queryResultCache のエントリに対してキャッシュするドキュメントの最大数を設定します。

<queryResultMaxDocsCached>200</queryResultMaxDocsCached>

<useColdSearcher> 要素

この設定は、現在登録されている検索者が存在しない検索リクエストで、新しい検索者がウォーミングアップするのを待機する必要があるか (false)、またはすぐに続行する必要があるか (true) を制御します。false に設定すると、リクエストは検索者がキャッシュをウォーミングアップするまでブロックされます。

<useColdSearcher>false</useColdSearcher>

<maxWarmingSearchers> 要素

このパラメータは、バックグラウンドでウォーミングアップできる検索者の最大数を設定します。この制限を超えると、エラーが発生します。

読み取り専用のフォロワーの場合、値 2 は妥当です。リーダーは、おそらく少し高く設定する必要があります。

<maxWarmingSearchers>2</maxWarmingSearchers>

キャッシュ」のセクションで説明したように、新しい Searcher はキャッシュされます。リスナーのトリガーを使用して、クエリ関連のタスクを実行できます。この最も一般的な用途は、Searcher の開始中に Searcher をさらに「ウォーミング」するためにクエリを定義することです。このアプローチの 1 つの利点は、フィールドキャッシュが、より高速なソートのために事前に入力されることです。

このタイプのリスナーでは、適切なクエリの選択が重要です。最も一般的または最も負荷の高いクエリを選択し、使用されているキーワードだけでなく、ソートやフィルタリングリクエストなどの他のパラメータも含めるのが最善です。

リスナーをトリガーできるイベントには、2 つのタイプがあります。

  1. firstSearcher イベントは、新しい検索者が準備されているが、リクエストを処理したり、自動ウォーミングデータを得るための現在の登録済み検索者が存在しない場合(つまり、Solr起動時)に発生します。

  2. newSearcher イベントは、コミット後など、新しい検索者が準備され、リクエストを処理する現在の検索者が存在する場合に常に発生します。

以下の(コメントアウトされた)例は、Solrに付属のsample_techproducts_configs configsetsolrconfig.xml ファイルにあり、solr.QuerySenderListener クラスを使用して、一連の明示的なクエリをウォーミングする方法を示しています。

<listener event="newSearcher" class="solr.QuerySenderListener">
  <arr name="queries">
  <!--
    <lst><str name="q">solr</str><str name="sort">price asc</str></lst>
    <lst><str name="q">rocks</str><str name="sort">weight asc</str></lst>
   -->
  </arr>
</listener>

<listener event="firstSearcher" class="solr.QuerySenderListener">
  <arr name="queries">
    <lst><str name="q">static firstSearcher warming in solrconfig.xml</str></lst>
  </arr>
</listener>

上記のコードは、サンプルsolrconfig.xml から抜粋したものです。

重要なベストプラクティスは、アプリケーションを本番環境に移行する前にこれらのデフォルト値を変更することですが、注意してください。「newSearcher」のセクションではサンプルクエリがコメントアウトされていますが、「firstSearcher」イベントではサンプルクエリはコメントアウトされていません。

検索アプリケーションに関係のない「static firstSearcher warming in solrconfig.xml」というクエリ文字列で検索者を自動ウォーミングしても意味がありません。

Config APIを使用したウォーミングクエリの管理

ウォーミングクエリは、以下のようなコマンドを使用して、Config APIを使用して管理できます。

異なるname属性を持つ複数のセットを提供でき、変更は再起動を必要とせずに即座に適用されます。

ウォーミングクエリセットの追加

ウォーミングクエリのセットを追加するには、add-listener コマンドを使用します。(別のコマンドとnamefirstSearcherクエリも提供することもできます。)

{
  "add-listener": {
    "name": "my-warming-queries",
    "event": "newSearcher",
    "class": "solr.QuerySenderListener",
    "queries": [
      { "q": "solr", "sort": "price asc" }
    ]
  }
}

クエリセットの更新

セットを更新するには、update-listener コマンドを使用します。セット全体が置き換えられることに注意してください。

{
  "update-listener": {
    "name": "my-warming-queries",
    "event": "newSearcher",
    "class": "solr.QuerySenderListener",
    "queries": [
      { "q": "solr", "sort": "price asc" },
      { "q": "rocks", "sort": "weight asc" }
    ]
  }
}

solrconfig.xmlでウォーミングクエリが定義されている場合、各<listener>要素にname属性を追加すると、Config APIを使用して上書きできます。

クエリセットの削除

クエリのセットを削除するには、delete-listenerを使用します。

{
  "delete-listener": "my-warming-queries"
}

solrconfig.xmlで元々定義されたウォーミングクエリセットの場合、delete-listenerコマンドを使用すると、ウォーミングクエリを削除するのではなく、solrconfig.xmlセットに戻ります。