Update Handler を使用したインデックス作成

更新ハンドラーは、インデックスにドキュメントを追加、削除、更新するように設計されたリクエストハンドラーです。リッチドキュメントをインポートするプラグイン(Solr Cell と Apache Tika を使用したインデックス作成を参照)に加えて、Solr は XML、CSV、および JSON で構造化されたドキュメントのインデックス作成をネイティブにサポートしています。

リクエストハンドラーを設定および使用する推奨方法は、リクエスト URL のパスにマップされるパスベースの名前を使用することです。ただし、requestDispatcher が適切に設定されている場合、リクエストハンドラーは qt (クエリタイプ) パラメーターを使用して指定することもできます。異なるデフォルトオプションのセットを指定したい場合に便利なように、複数の名前を使用して同じハンドラーにアクセスすることができます。

単一の統合更新リクエストハンドラーは、XML、CSV、JSON、および javabin 更新リクエストをサポートし、ContentStreamContent-Type に基づいて適切な ContentStreamLoader に委譲します。

ドキュメントをロードした後、インデックスが作成される前 (またはスキーマに対してチェックされる前) に前処理する必要がある場合、Solr には 更新リクエストプロセッサーと呼ばれる更新リクエストハンドラー用のドキュメント前処理プラグインがあり、デフォルトおよびカスタム設定チェーンを可能にします。

UpdateRequestHandler の設定

デフォルトの設定ファイルには、更新リクエストハンドラーがデフォルトで設定されています。

<requestHandler name="/update" class="solr.UpdateRequestHandler" />

XML 形式のインデックス更新

インデックス更新コマンドは、Content-type: application/xml または Content-type: text/xml を使用して、XML メッセージとして更新ハンドラーに送信できます。

ドキュメントの追加

ドキュメントを追加するための更新ハンドラーで認識される XML スキーマは非常に簡単です。

  • <add> 要素は、追加する 1 つ以上のドキュメントを導入します。

  • <doc> 要素は、ドキュメントを構成するフィールドを導入します。

  • <field> 要素は、特定のフィールドのコンテンツを示します。

例:

<add>
  <doc>
    <field name="authors">Patrick Eagar</field>
    <field name="subject">Sports</field>
    <field name="dd">796.35</field>
    <field name="numpages">128</field>
    <field name="desc"></field>
    <field name="price">12.40</field>
    <field name="title">Summer of the all-rounder: Test and championship cricket in England 1982</field>
    <field name="isbn">0002166313</field>
    <field name="yearpub">1982</field>
    <field name="publisher">Collins</field>
  </doc>
  <doc>
  ...
  </doc>
</add>

add コマンドは、指定可能ないくつかのオプションの属性をサポートしています。

commitWithin

オプション

デフォルト: なし

指定されたミリ秒数以内にドキュメントを追加します。

overwrite

オプション

デフォルト: true

一意のキー制約をチェックして、同じドキュメントの以前のバージョンを上書きするかどうかを示します (下記参照)。

ドキュメントスキーマが一意キーを定義している場合、デフォルトでは、ドキュメントを追加する/update操作は、同じ一意キーを持つインデックス内のドキュメントを上書き(つまり、置き換え)します。一意キーが定義されていない場合、既存のドキュメントを置き換えるためのチェックを行う必要がないため、インデックス作成のパフォーマンスが若干向上します。

一意キーフィールドがあるものの、一意性チェックを安全にバイパスできると確信できる場合(たとえば、インデックスをバッチで構築し、インデックス作成コードが同じドキュメントを複数回追加しないことを保証する場合)、ドキュメントを追加する際にoverwrite="false"オプションを指定できます。

XML更新コマンド

更新中のコミットと最適化

<commit>操作は、最後のコミット以降にロードされたすべてのドキュメントをディスク上の一または複数のセグメントファイルに書き込みます。コミットが発行されるまで、新しくインデックス付けされたコンテンツは検索に表示されません。コミット操作は新しい検索者を開き、構成されているイベントリスナーをトリガーします。

コミットは、<commit/>メッセージで明示的に発行できます。また、solrconfig.xml<autocommit>パラメータからトリガーすることもできます。

<optimize>操作は、Solrに内部データ構造のマージを要求します。大規模なインデックスの場合、最適化の完了には時間がかかりますが、多数の小さなセグメントファイルを大きなセグメントにマージすることで、検索パフォーマンスが向上する可能性があります。Solrのレプリケーションメカニズムを使用して多数のシステムに検索を分散する場合は、最適化後にインデックス全体を転送する必要があることに注意してください。

最適化は、静的インデックス、つまり、定期的な更新プロセスの一部として最適化できるインデックス(たとえば、1日1回の更新)でのみ使用を検討する必要があります。NRT機能を必要とするアプリケーションは最適化を使用すべきではありません。

<commit>要素と<optimize>要素は、次のオプション属性を受け入れます。

waitSearcher

オプション

デフォルト: true

新しい検索者が開かれ、メインのクエリ検索者として登録され、変更が表示されるようになるまでブロックします。

expungeDeletes

オプション

デフォルト: false

10%を超える削除されたドキュメントがあるセグメントをマージし、その過程で削除されたドキュメントを削除します。結果として得られるセグメントはmaxMergedSegmentMBを尊重します。このオプションは<commit>操作でのみ適用されます。

expungeDeletesは最適化よりもコストが低いですが、同じ警告が適用されます。
maxSegments

オプション

デフォルト: なし

セグメントをこの数以下のセグメントにマージするように最善を尽くしますが、目標が達成されるとは限りません。少数のセグメントへの最適化が有益であるという具体的な証拠がない限り、このパラメータは省略し、デフォルトの動作を受け入れる必要があります。このオプションは<optimize操作でのみ適用されます。デフォルトは無制限で、結果のセグメントはmaxMergedSegmentMB設定を尊重します。

オプション属性を使用した<commit><optimize>の例を次に示します。

<commit waitSearcher="false"/>
<commit waitSearcher="false" expungeDeletes="true"/>
<optimize waitSearcher="false"/>

削除操作

ドキュメントは、2つの方法でインデックスから削除できます。「IDによる削除」は、指定されたIDを持つドキュメントを削除し、スキーマでUniqueIDフィールドが定義されている場合にのみ使用できます。子/ネストされたドキュメントでは機能しません。「クエリによる削除」は、指定されたクエリに一致するすべてのドキュメントを削除しますが、クエリによる削除ではcommitWithinは無視されます。単一の削除メッセージに複数の削除操作を含めることができます。

<delete>
  <id>0002166313</id>
  <id>0031745983</id>
  <query>subject:sport</query>
  <query>publisher:penguin</query>
</delete>

クエリによる削除でJoinクエリパーサーを使用する場合は、ClassCastExceptionを回避するために、値が「none」のscoreパラメータを使用する必要があります。scoreパラメータの詳細については、Joinクエリパーサーのセクションを参照してください。

ロールバック操作

ロールバックコマンドは、最後のコミット以降に行われたインデックスへの追加と削除をすべてロールバックします。イベントリスナーを呼び出したり、新しい検索者を作成したりすることはありません。構文は単純です:<rollback/>

グループ化操作

複数のコマンドを単一のXMLファイルに投稿するには、それらを囲む<update>要素でグループ化します。

<update>
  <add>
    <doc><!-- doc 1 content --></doc>
  </add>
  <add>
    <doc><!-- doc 2 content --></doc>
  </add>
  <delete>
    <id>0002166313</id>
  </delete>
</update>

curlを使用して更新を実行する

curlユーティリティを使用して上記のコマンドを実行できます。その--data-binaryオプションを使用してXMLメッセージをcurlコマンドに追加し、HTTP POSTリクエストを生成します。例:

curl https://127.0.0.1:8983/solr/my_collection/update -H "Content-Type: text/xml" --data-binary '
<add>
  <doc>
    <field name="authors">Patrick Eagar</field>
    <field name="subject">Sports</field>
    <field name="dd">796.35</field>
    <field name="isbn">0002166313</field>
    <field name="yearpub">1982</field>
    <field name="publisher">Collins</field>
  </doc>
</add>'

ファイルに含まれるXMLメッセージを投稿するには、代替形式を使用できます。

curl https://127.0.0.1:8983/solr/my_collection/update -H "Content-Type: text/xml" --data-binary @myfile.xml

上記の方法はうまく機能しますが、--data-binaryオプションを使用すると、curlmyfile.xml全体をメモリにロードしてからサーバーに投稿します。これは、数ギガバイトのファイルを扱う場合に問題になる可能性があります。この代替のcurlコマンドは、同等の操作を実行しますが、curlのメモリ使用量を最小限に抑えます。

curl https://127.0.0.1:8983/solr/my_collection/update -H "Content-Type: text/xml" -T "myfile.xml" -X POST

HTTP GETコマンドを使用して短いリクエストを送信することもできます。solrconfig.xmlrequestParsers要素で有効になっている場合は、以下のように、リクエストをURLエンコードします。「<」と「>」のエスケープに注意してください。

curl https://127.0.0.1:8983/solr/my_collection/update?stream.body=%3Ccommit/%3E&wt=xml

Solrからの応答は、ここに示されている形式になります。

<response>
  <lst name="responseHeader">
    <int name="status">0</int>
    <int name="QTime">127</int>
  </lst>
</response>

失敗した場合、statusフィールドはゼロ以外になります。

XSLTを使用してXMLインデックス更新を変換する

スクリプトモジュールは、<tr>パラメータを使用してXSL変換を適用することで、任意のXMLをインデックス付けできる個別のXSLT更新リクエストハンドラーを提供します。着信データを予期される<add><doc/></add>形式に変換できるXSLTスタイルシートが、configsetconf/xsltディレクトリに必要です。また、trパラメータを使用して、そのスタイルシートの名前を指定する必要があります。

この機能を使用する前に、スクリプトモジュールを有効にする必要があります。

trパラメータ

XSLT更新リクエストハンドラーは、使用するXML変換を識別するtrパラメータを受け入れます。変換はSolrのconf/xsltディレクトリに存在する必要があります。

XSLT構成

以下の例は、Solrディストリビューションのsample_techproducts_configsconfigsetからのもので、XSLT更新リクエストハンドラーがどのように構成されているかを示しています。

<!--
  Changes to XSLT transforms are taken into account
  every xsltCacheLifetimeSeconds at most.
-->
<requestHandler name="/update/xslt"
                     class="solr.scripting.xslt.XSLTUpdateRequestHandler">
  <int name="xsltCacheLifetimeSeconds">5</int>
</requestHandler>

xsltCacheLifetimeSecondsの値が5であることは、XSLTの変更をすばやく確認できるため、開発に適しています。実稼働環境では、より高い値が必要になるでしょう。

XSLT更新の例

標準のSolr XML出力をSolrが予期する<add><doc/></add>形式に変換するためのsample_techproducts_configs/conf/xslt/updateXml.xsl XSLファイルを次に示します。

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:output media-type="text/xml" method="xml" indent="yes"/>
  <xsl:template match='/'>
    <add>
      <xsl:apply-templates select="response/result/doc"/>
    </add>
  </xsl:template>
  <!-- Ignore score (makes no sense to index) -->
  <xsl:template match="doc/*[@name='score']" priority="100"></xsl:template>
  <xsl:template match="doc">
    <xsl:variable name="pos" select="position()"/>
    <doc>
      <xsl:apply-templates>
        <xsl:with-param name="pos"><xsl:value-of select="$pos"/></xsl:with-param>
      </xsl:apply-templates>
    </doc>
  </xsl:template>
  <!-- Flatten arrays to duplicate field lines -->
  <xsl:template match="doc/arr" priority="100">
    <xsl:variable name="fn" select="@name"/>
    <xsl:for-each select="*">
      <xsl:element name="field">
        <xsl:attribute name="name"><xsl:value-of select="$fn"/></xsl:attribute>
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="doc/*">
    <xsl:variable name="fn" select="@name"/>
      <xsl:element name="field">
        <xsl:attribute name="name"><xsl:value-of select="$fn"/></xsl:attribute>
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="*"/>
</xsl:stylesheet>

このスタイルシートは、SolrのXML検索結果形式をSolrの更新XML構文に変換します。使用例の1つは、別のSolrファイルにインデックスを付けることができる形式に、Solr 1.3インデックス(CSVレスポンスライターがない)をコピーすることです(すべてのフィールドが保存されている場合)。

$ curl -o standard_solr_xml_format.xml "https://127.0.0.1:8983/solr/techproducts/select?q=ipod&fl=id,cat,name,popularity,price,score&wt=xml"

$ curl -X POST -H "Content-Type: text/xml" -d @standard_solr_xml_format.xml "https://127.0.0.1:8983/solr/techproducts/update/xslt?commit=true&tr=updateXml.xsl"
レスポンスライターXSLTの例では、trパラメータを使用した反対のエクスポート/インポートサイクルを確認できます。

JSON形式のインデックス更新

Solrは、定義された構造に準拠するJSONを受け入れることも、任意のJSON形式のドキュメントを受け入れることもできます。任意の形式のJSONを送信する場合は、カスタムJSONの変換とインデックス作成のセクションで説明されているように、更新リクエストと共に送信する必要がある追加のパラメータがいくつかあります。

SolrスタイルのJSON

JSON形式の更新リクエストは、Content-Type: application/jsonまたはContent-Type: text/jsonを使用して、Solrの/updateハンドラーに送信できます。

JSON形式の更新は、以下で詳しく説明するように、3つの基本的な形式を取ることができます。

  • 単一のドキュメント。最上位のJSONオブジェクトとして表現されます。コマンドのセットと区別するために、json.command=falseリクエストパラメータが必要です。

  • ドキュメントのリスト。ドキュメントごとにJSONオブジェクトを含む最上位のJSON配列として表現されます。

  • 更新コマンドのシーケンス。最上位のJSONオブジェクト(マップ)として表現されます。

単一のJSONドキュメントの追加

JSONを介してドキュメントを追加する最も簡単な方法は、/update/json/docsパスを使用して、各ドキュメントを個別にJSONオブジェクトとして送信することです。

curl -X POST -H 'Content-Type: application/json' 'https://127.0.0.1:8983/solr/my_collection/update/json/docs' --data-binary '
{
  "id": "1",
  "title": "Doc 1"
}'

複数のJSONドキュメントの追加

JSONを介して一度に複数のドキュメントを追加するには、JSONオブジェクトのJSON配列を介して行うことができます。各オブジェクトはドキュメントを表します。

curl -X POST -H 'Content-Type: application/json' 'https://127.0.0.1:8983/solr/my_collection/update' --data-binary '
[
  {
    "id": "1",
    "title": "Doc 1"
  },
  {
    "id": "2",
    "title": "Doc 2"
  }
]'

サンプルJSONファイルは、example/exampledocs/books.jsonにあり、Solrの「techproducts」の例に追加できるオブジェクトの配列が含まれています。

curl 'https://127.0.0.1:8983/solr/techproducts/update?commit=true' --data-binary @example/exampledocs/books.json -H 'Content-type:application/json'

JSON更新コマンドの送信

一般に、JSON更新構文は、XML更新ハンドラーがサポートするすべての更新コマンドを、簡単なマッピングを通じてサポートしています。複数のコマンド、ドキュメントの追加と削除を1つのメッセージに含めることができます。

curl -X POST -H 'Content-Type: application/json' 'https://127.0.0.1:8983/solr/my_collection/update' --data-binary '
{
  "add": {
    "doc": {
      "id": "DOC1",
      "my_field": 2.3,
      "my_multivalued_field": [ "aaa", "bbb" ]   (1)
    }
  },
  "add": {
    "commitWithin": 5000, (2)
    "overwrite": false,  (3)
    "doc": {
      "f1": "v1", (4)
      "f1": "v2"
    }
  },

  "commit": {},
  "optimize": { "waitSearcher":false },

  "delete": { "id":"ID" },  (5)
  "delete": { "query":"QUERY" } (6)
}'
1 複数値フィールドには配列を使用できます。
2 このドキュメントを5秒以内にコミットします。
3 同じuniqueKeyを持つ既存のドキュメントを確認しないでください。
4 複数値フィールドには繰り返しキーを使用できます。
5 ID(uniqueKeyフィールド)による削除
6 クエリによる削除

他の更新ハンドラーと同様に、commitcommitWithinoptimize、およびoverwriteなどのパラメータは、メッセージの本文ではなく、URLで指定できます。

JSON更新形式では、IDによる簡単な削除が可能です。deleteの値には、削除する特定のドキュメントIDのリスト(範囲ではない)がゼロ個以上含まれる配列を指定できます。たとえば、単一のドキュメント

{ "delete":"myid" }

またはドキュメントIDのリスト

{ "delete":["id1","id2"] }

注: IDによる削除は、子/ネストされたドキュメントでは機能しません。

各「削除」で_version_を指定することもできます。

{
  "delete":"id":50,
  "_version_":12345
}

更新リクエストの本文で削除のバージョンを指定することもできます。

JSON更新の便利なパス

/updateハンドラーに加えて、Solrにはデフォルトで利用可能なJSON固有の追加のリクエストハンドラーパスがいくつかあり、一部のリクエストパラメータの動作を暗黙的にオーバーライドします。

パス デフォルトパラメータ

/update/json

stream.contentType=application/json

/update/json/docs

stream.contentType=application/json

json.command=false

/update/json パスは、Content-Type の設定が難しいアプリケーションから JSON 形式の更新コマンドを送信するクライアントにとって便利な場合があります。一方、/update/json/docs パスは、完全な JSON コマンド構文を気にすることなく、ドキュメントを個別にまたはリストとして常に送信したいクライアントにとって特に便利です。

カスタム JSON ドキュメント

Solr はカスタム JSON をサポートできます。これについては、「カスタム JSON の変換とインデックス作成」のセクションで説明します。

CSV 形式のインデックス更新

CSV 形式の更新リクエストは、Content-Type: application/csv または Content-Type: text/csv を使用して Solr の /update ハンドラーに送信できます。

サンプル CSV ファイルは example/exampledocs/books.csv に用意されており、Solr の "techproducts" 例にいくつかのドキュメントを追加するために使用できます。

curl 'https://127.0.0.1:8983/solr/my_collection/update?commit=true' --data-binary @example/exampledocs/books.csv -H 'Content-type:application/csv'

CSV 更新パラメータ

CSV ハンドラーでは、URL に f.parameter.optional_fieldname=value の形式で多くのパラメータを指定できます。

以下の表に、更新ハンドラーのパラメータを示します。

separator

オプション

デフォルト: ,

フィールド区切り文字として使用される文字。このパラメータはグローバルです。フィールドごとの使用法については、split パラメータを参照してください。

例: separator=%09

trim

オプション

デフォルト: false

true の場合、値の先頭と末尾の空白を削除します。このパラメータはグローバルまたはフィールドごとに設定できます。

例: f.isbn.trim=true または trim=false

header

オプション

デフォルト: true

入力の最初の行にフィールド名が含まれている場合は true に設定します。これらは fieldnames パラメータがない場合に使用されます。このパラメータはグローバルです。

fieldnames

オプション

デフォルト: なし

ドキュメントを追加する際に使用するフィールド名のカンマ区切りリスト。このパラメータはグローバルです。

例: fieldnames=isbn,price,title

literal.field_name

オプション

デフォルト: なし

指定されたフィールド名のリテラル値。このパラメータはグローバルです。

例: literal.color=red

skip

オプション

デフォルト: なし

スキップするフィールド名のカンマ区切りリスト。このパラメータはグローバルです。

例: skip=uninteresting,shoesize

skipLines

オプション

デフォルト: 0

CSV データが開始する前に、ヘッダーが含まれている場合はヘッダーも含めて、入力ストリームで破棄する行数。このパラメータはグローバルです。

例: skipLines=5

encapsulator

オプション

デフォルト: なし

CSV セパレータや空白などの文字を保持するために、値を囲むためにオプションで使用される文字。この標準的な CSV 形式では、カプセル化された値にカプセル化子自体が現れる場合、カプセル化子を二重化することで処理します。

このパラメータはグローバルです。フィールドごとの使用法については、split を参照してください。

例: encapsulator="

escape

オプション

デフォルト: なし

CSV 区切り文字またはその他の予約文字をエスケープするために使用される文字。エスケープが指定されている場合、ほとんどの形式ではカプセル化またはエスケープのどちらか一方を使用し、両方を使用しないため、明示的に指定しない限り、カプセル化子は使用されません。

例: escape=\

keepEmpty

オプション

デフォルト: false

ゼロ長 (空) フィールドを保持し、インデックスを作成します。このパラメータはグローバルまたはフィールドごとに設定できます。

例: f.price.keepEmpty=true

map

オプション

デフォルト: なし

ある値を別の値にマッピングします。形式は map=value:replacement です (空にすることもできます)。このパラメータはグローバルまたはフィールドごとに設定できます。

例: map=left:right または f.subject.map=history:bunk

split

オプション

デフォルト: なし

true の場合、個別のパーサーによってフィールドを複数の値に分割します。このパラメータは、f.FIELD_NAME_GOES_HERE.split=true のように、フィールドごとに使用されます。

overwrite

オプション

デフォルト: true

true の場合、Solr スキーマで宣言された uniqueKey フィールドに基づいて、重複したドキュメントを確認し、上書きします。インデックスを作成するドキュメントに重複が含まれていないことがわかっている場合は、これを false に設定することで大幅な高速化が期待できます。

このパラメータはグローバルです。

commit

オプション

デフォルト: なし

データが取り込まれた後にコミットを発行します。このパラメータはグローバルです。

commitWithin

オプション

デフォルト: なし

指定されたミリ秒以内にドキュメントを追加します。このパラメータはグローバルです。

例: commitWithin=10000

rowid

オプション

デフォルト: なし

パラメータの値で指定されたフィールドに rowid (行番号) をマッピングします。たとえば、CSV に一意のキーがなく、行 ID をキーとして使用したい場合などに使用します。このパラメータはグローバルです。

例: rowid=id

rowidOffset

オプション

デフォルト: 0

ドキュメントに追加する前に、指定されたオフセット (整数) を rowid に追加します。このパラメータはグローバルです。

例: rowidOffset=10

タブ区切りファイルのインデックス作成

CSV ドキュメントのインデックス作成に使用される同じ機能は、タブ区切りファイル (TSV ファイル) のインデックス作成にも簡単に使用でき、CSV カプセル化ではなくバックスラッシュエスケープも処理できます。

たとえば、MySQL テーブルをタブ区切りファイルにダンプするには、次のようにします。

SELECT * INTO OUTFILE '/tmp/result.txt' FROM mytable;

このファイルは、separator をタブ (%09) に、escape をバックスラッシュ (%5c) に設定することで、Solr にインポートできます。

curl 'https://127.0.0.1:8983/solr/my_collection/update/csv?commit=true&separator=%09&escape=%5c' --data-binary @/tmp/result.txt

CSV 更新の便利なパス

/update ハンドラーに加えて、Solr にはデフォルトで追加の CSV 固有のリクエスト ハンドラー パスがあり、一部のリクエスト パラメータの動作を暗黙的に上書きします。

パス デフォルトパラメータ

/update/csv

stream.contentType=application/csv

/update/csv パスは、Content-Type の設定が難しいアプリケーションから CSV 形式の更新コマンドを送信するクライアントにとって便利な場合があります。