タグ: Solr

[Solr]分散検索でどのレプリカに検索リクエストを送るのかを制御する

SolrCloud でシャードに複数のレプリカを作った場合、検索リクエストを処理する際にどのレプリカを優先するのかを shards.preference パラメータで指定できます。

以下の形式で優先順を指定します。
shards.preference=属性1:値1,属性2:値2,…
左側にあるものほど優先度が高くなります。

指定できる属性は以下の通りです。

replica.type

レプリカの種類(PULL, TLOG, NRT)を指定します

replica.location

http://hostname:port から始まる文字列でレプリカの場所を指定します。前方一致でレプリカを選びます。

特殊なケースとして “local” を指定した場合、リクエストを処理するサーバと同じサーバにある Solr インスタンスのレプリカが選ばれます。フィールド数が多い、巨大なフィールドがある、などの理由で検索結果のデータサイズが大きい場合に有効です。特定のレプリカに障害が発生した場合の影響範囲を小さくする効果もあります。

replica.base

優先順位が同じレプリカが存在するときに、それらの間でどれを優先するかを決めるためのルールを指定します。

  • random ランダムに1つ選びます
  • stable:dividend:パラメータ名 指定したパラメータに対応する整数値をレプリカ数で割った余りで決定します
  • stable[:hash[:パラメータ名]] 指定したパラメータに対応する文字列のハッシュ値をレプリカ数で割った余りで決定します。パラメータ名が指定されない場合はメインのクエリである q の値が使われます。

node.sysprop

指定したシステムプロパティの値が同じレプリカが選ばれます。
たとえば同じラックに属する Solr インスタンスが同じ rack プロパティの値を持つように -Drack=rack1 のように設定しておき、検索時に shards.preference=node.sysprop:sysprop.rack を指定すると、リクエストを処理している Solr インスタンスと同じ rack プロパティの値を持つ(=同じラックに属する)レプリカが選ばれます。

replica.leader

リーダーレプリカを優先するかどうかを true または false で指定します。たとえばレプリカが6台ある状態で replica.leader:false が指定されるとリーダー以外の5台が分散検索の対象となります。

SolrCloudにおけるレプリカの種類

ドキュメント数の非常に多いコレクションを扱う場合、複数のシャードを作ってデータを分けることができます。ドキュメントはそれぞれ複数のシャードのどれか1箇所にだけ属します。
シャードは1個以上のレプリカから構成されます。同じシャードに属するレプリカの内容はすべて同じです。シャードのうちどれか一つがリーダーとして選ばれます。

インデックス対象のドキュメントがSolrに送られてきたとき、まずそのドキュメントがどのシャードに属するべきかが決定され、そのシャードのリーダーにドキュメントが送られます。そして同じシャードに属する他のレプリカすべてにリーダーからドキュメントが転送されます。

レプリカにはいくつか種類があります。

NRT(= NearRealTime)

  • デフォルトの設定。トランザクションログを保持しつつ自身のローカルのインデックスの更新も行う。
  • リーダー選出の候補となる。

TLOG

  • トランザクションログの維持はするが、自身ではローカルのインデックス更新は行わない。
  • このタイプのレプリカはコミットを実行する必要が無いのでインデックスの速度向上が見込める。
  • このタイプのレプリカでインデックスを更新するには、リーダーからインデックスをレプリケートする。
  • リーダー選出の候補となる。
  • もしもリーダーに選出された場合には、NRTレプリカと同様に動作する。

PULL

  • トランザクションログの維持もローカルのインデックス更新もせず、リーダーのインデックスのレプリケーションのみを行う。
  • リーダー選出の候補にはならない。

レプリカのうちどれかはリーダーにならなければならないので、シャードのレプリカをすべてPULLだけで構成することはできません。
Solrリファレンスでお薦めされているレプリカタイプの組み合わせは以下の通りです。

すべてNRT

更新のリアルタイム性が必要でありインデックス更新のスループットがそれほど大きくない場合、この組み合わせにする。
特にSoft Commitが必要な場合はNRTしか選択肢が無い。

すべてTLOG

インデックス更新のリアルタイム性が必要でなくシャード内のレプリカが非常に多い場合、すべてのレプリカで更新リクエストを扱えるようにしておきたいと考えるならば、この組み合わせにする。

TLOGとPULLの組み合わせ

インデックス更新のリアルタイム性が必要でなくシャード内のレプリカが非常に多い場合、多少古い検索結果を許容しつつ検索クエリへの応答能力拡大をするにはこの組み合わせにする。

Solr 8.10 で追加された Schema Designer UI

はじめに

Solr 8.10 で管理画面に Schema Designer UI が追加されました。
https://solr.apache.org/guide/8_10/schema-designer.html

  • ドキュメントのサンプルからスキーマを作ってくれる
  • スキーマをGUIで編集できる
  • 編集中のスキーマの設定でクエリがどんな動きになるか動作確認できる
  • 作ったスキーマに基づいたコレクションを作成できる

と至れり尽くせりです。

使い方

名前を付けて新しいスキーマを作る

スキーマの名前と、元になる設定の名前を与えて新しいスキーマを作成します。

ドキュメントのサンプルを与えてスキーマの設定を生成する

インデックス対象のドキュメントをテキストエリアに貼り付けるか、ファイルを指定するかして与えます。ドキュメントは1個でも解析してスキーマを作ってくれますが、ドキュメントを複数与えておけば、後でクエリの動作を確認するときに色々なパターンを試せます。

今回サンプルとして与えたのは以下のようなドキュメントです。

[
{"id":"10","type":"官公庁","area":"住之江区","name":"軽自動車検査協会大阪主管事務所","address":"住之江区南港東3-4-62","address_p":"34.6164938333333,135.438210722222"},
{"id":"11","type":"官公庁","area":"住之江区","name":"大阪陸運支局なにわ自動車検査登録事務所","address":"住之江区南港東3-1-14","address_p":"34.6190439722222,135.442191833333"},
{"id":"12","type":"官公庁","area":"住吉区","name":"住吉税務署","address":"住吉区住吉2丁目17番37号","address_p":"34.6109641111111,135.491388722222"}
]

生成されたスキーマの画面です。
JSONでフィールド名を与えているのでフィールド名が正しいのは当然として、サンプルの内容を解析してフィールドタイプもそれなりに妥当なものを選んでくれます。
たとえば上のように、緯度経度を値に持つ address_p フィールドに対して location タイプが選ばれています。

スキーマの設定を変更する

設定を変更することもできます。 住所を格納する address フィールドに対して string タイプが選ばれていましたが、ここでは形態素解析をする text_ja フィールドに変更しました。

Analyzer の動作を確認する

形態素解析をするフィールドでどのような解析が行われるか動作確認ができます。

クエリの動作を確認する

現在のスキーマの設定でクエリがどのように動くかを確認できます。

このときクエリの対象となるのが、最初に与えたサンプルドキュメントになります。今回はドキュメントを3件(id が 10, 11, 12)与えたので、全件検索で3件ヒットしています。

area フィールドを対象としたファセットで「住之江区」が2件、「住吉区」が1件となることも分かります。

変更前の設定との差分を確認する

元になった設定(_default)からの、現在の設定の変更点を表示します。

作成したスキーマを利用してコレクションを生成する

生成した設定は Zookeeper のツリー上に保存されますが、この設定を利用して一気にコレクションを生成することもできます。

[Solr]更新の際に _route_ パラメータは指定しない方が良い

今回は小ネタです。

SolrCloud でとある検証をしているときに不思議な現象に気付きました。

ドキュメント1を追加
→ 全件検索でドキュメント1がヒットする
→ ドキュメント2を追加
→ 全件検索でドキュメント2だけがヒットする
→ ドキュメント3を追加
→ 全件検索でドキュメント3だけがヒットする
→ …

要するに、新しいドキュメントを追加するとそれ以前のドキュメントが消えるという現象です。

いろいろ試すうちに、あるスクリプトを使って更新した場合にこの現象が発生し、別のスクリプトでは発生しないことが分かりました。2つのスクリプトを比較することで、問題が起こる方では update の際に _route_ パラメータを指定していることが分かりました。

コレクションを CREATE するときに _route_ パラメータを指定していれば update のときに _route_ を指定する必要はありませんが、どのフィールド値でルーティングしているのかが分かりやすいように明示的に _route_ を書いたのが仇となったようです。

ログを見ても _route_ パラメータ有りの場合と無しの場合とで目立った違いは無く、どうしてこうなるのかを調べるにはソースを深く追っかけてみるしかなさそうです。

【Solr】検索結果のグループ化(Collapse and Expand)

以前、グループ検索の手段として Result Grouping を紹介しました。
もう一つの手段として Collapse and Expand があります。 Collapse を辞書で引くと「つぶれる」とか「崩れる」とか出てきて少しイメージのしにくい言葉ですが、たとえばファイルビューアで言うと

↓これが Collapse している状態

↓これが Expand している状態

と捉えると分かりやすいかと思います。

Solr における検索結果の Collapse とは特定のフィールドの値に基づいて検索結果をグループ分けし、各グループの代表ドキュメントを出力することであり、Expand とは Collapse で作られた各グループに属するドキュメントを選択して出力することです。

Collapsing は CollapsingQParser で実装されており、フィルタクエリで指定します。以下は大阪の施設情報を施設タイプ(typeフィールド)でグルーピングするクエリ例です。

$ curl http://localhost:8983/solr/osaka_shisetsu/select -d 'q=*:*&rows=3&omitHeader=true&fq={!collapse field=type}'
{
  "response":{"numFound":13,"start":0,"numFoundExact":true,"docs":[
      {
        "id":"10",
        "type":"官公庁",
        "area":"住之江区",
        "name":"軽自動車検査協会大阪主管事務所",
        "address":["住之江区南港東3-4-62"],
        "address_p":"34.6164938333333,135.438210722222",
        "_version_":1695487381634809856},
      {
        "id":"311",
        "type":"学校・保育所",
        "area":"住之江区",
        "name":"大和幼稚園",
        "address":["大阪市住之江区北島3-3-11"],
        "address_p":"34.6013536388888,135.478355305555",
        "_version_":1695487381872836611},
      {
        "id":"1356",
        "type":"公園・スポーツ",
        "area":"住之江区",
        "name":"住之江公園プール",
        "address":["住之江区南加賀屋1住之江公園内"],
        "address_p":"34.6118221111111,135.473814305555",
        "_version_":1695487382023831552}]
  }}

各グループ5件ずつのドキュメントが欲しい、といった場合には expand=true を指定します。以下は、typeフィールドでグループ化して、各グループ2件ずつのドキュメントを取得するクエリ例です。

$ curl --user solr:SolrRocks http://localhost:8983/solr/osaka_shisetsu/select -d 'q=*:*&rows=3&omitHeader=true&fq={!collapse field=type}&expand=true&expand.rows=2'
{
  "response":{"numFound":13,"start":0,"numFoundExact":true,"docs":[
      {
        "id":"10",
        "type":"官公庁",
        "area":"住之江区",
        "name":"軽自動車検査協会大阪主管事務所",
        "address":["住之江区南港東3-4-62"],
        "address_p":"34.6164938333333,135.438210722222",
        "_version_":1695487381634809856},
      {
        "id":"311",
        "type":"学校・保育所",
        "area":"住之江区",
        "name":"大和幼稚園",
        "address":["大阪市住之江区北島3-3-11"],
        "address_p":"34.6013536388888,135.478355305555",
        "_version_":1695487381872836611},
      {
        "id":"1356",
        "type":"公園・スポーツ",
        "area":"住之江区",
        "name":"住之江公園プール",
        "address":["住之江区南加賀屋1住之江公園内"],
        "address_p":"34.6118221111111,135.473814305555",
        "_version_":1695487382023831552}]
  },
  "expanded":{
    "公園・スポーツ":{"numFound":1089,"start":0,"numFoundExact":true,"docs":[
        {
          "id":"1357",
          "type":"公園・スポーツ",
          "area":"住之江区",
          "name":"住之江公園野球場",
          "address":["住之江区南加賀屋1住之江公園内"],
          "address_p":"34.6116668611111,135.475586222222",
          "_version_":1695487382023831553},
        {
          "id":"1358",
          "type":"公園・スポーツ",
          "area":"住之江区",
          "name":"住之江公園多目的広場",
          "address":["住之江区南加賀屋1住之江公園内"],
          "address_p":"34.6105608055555,135.475235888888",
          "_version_":1695487382023831554}]
    },
    "学校・保育所":{"numFound":1044,"start":0,"numFoundExact":true,"docs":[
        {
          "id":"312",
          "type":"学校・保育所",
          "area":"住吉区",
          "name":"大阪市立墨江幼稚園",
          "address":["住吉区墨江2丁目3番17号"],
          "address_p":"34.6077390555555,135.496024694444",
          "_version_":1695487381872836612},
        {
          "id":"313",
          "type":"学校・保育所",
          "area":"住之江区",
          "name":"加賀幼稚園",
          "address":["大阪市住之江区中加賀屋4-4-22"],
          "address_p":"34.6140463611111,135.478756833333",
          "_version_":1695487381872836613}]
    },
    "官公庁":{"numFound":300,"start":0,"numFoundExact":true,"docs":[
        {
          "id":"11",
          "type":"官公庁",
          "area":"住之江区",
          "name":"大阪陸運支局なにわ自動車検査登録事務所",
          "address":["住之江区南港東3-1-14"],
          "address_p":"34.6190439722222,135.442191833333",
          "_version_":1695487381820407808},
        {
          "id":"12",
          "type":"官公庁",
          "area":"住吉区",
          "name":"住吉税務署",
          "address":["住吉区住吉2丁目17番37号"],
          "address_p":"34.6109641111111,135.491388722222",
          "_version_":1695487381821456384}]
    }}}

この結果を使えば、まさに先程ファイルビューアの例で示したような検索結果の表示が実現できることが分かります。