スクリプト更新プロセッサ

ScriptUpdateProcessorFactoryを使用すると、Solrドキュメントの更新処理中にJavaスクリプトエンジンを使用できるようになり、インデックス化される前にカスタムドキュメント処理ロジックを非常に柔軟に表現できます。

コミット、削除、ロールバックなどのインデクシングアクションへのフックがありますが、追加が最も一般的な使用方法です。 UpdateChainに配置されるUpdateProcessorとして実装されています。

これは以前は*StatelessScriptingUpdateProcessor*として知られていましたが、この更新プロセッサの重要な側面がスクリプトを有効にすることを明確にするために名前が変更されました。

スクリプトは、JVMでサポートされている任意のスクリプト言語(JavaScriptなど)で記述でき、動的に実行されるため、プリコンパイルは必要ありません。

インデクシングパイプラインの一部として選択したスクリプトを実行できることは、非常に強力なツールです。これは、他の方法では解決できない問題をこの方法で解決できるため、*刑務所脱出無料*カードと呼ぶこともあります。ただし、潜在的なセキュリティの脆弱性がいくつか発生します。

モジュール

これは、使用する前に有効にする必要がある`scripting` Solrモジュールによって提供されます。

ScriptingUpdateProcessorとスクリプトエンジンの有効化

Java 11以前のバージョンにはNashornと呼ばれるJavaScriptエンジンが付属していますが、Java 12では独自のJavaScriptエンジンを追加する必要があります。 JRuby、Jython、Groovyなどの他のサポートされているスクリプトエンジンはすべて、SolrにJARファイルを追加する必要があります。

必要なJARファイル(スクリプトエンジンによって異なります)をSolrのライブラリディレクトリに追加する方法の詳細をご覧ください。

構成

<updateRequestProcessorChain name="script">
   <processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
     <str name="script">update-script.js</str>
   </processor>
   <!--  optional parameters passed to script
     <lst name="params">
       <str name="config_param">example config parameter</str>
     </lst>
   -->
   <processor class="solr.LogUpdateProcessorFactory" />
   <processor class="solr.RunUpdateProcessorFactory" />
 </updateRequestProcessorChain>
プロセッサは、設定のデフォルト/追加/不変の概念をサポートしています。ただし、このレベルをスキップして、`<processor>`タグの直下にパラメータを直接設定することもできます。

以下は、各構成パラメータとその意味のリストです。

スクリプト

必須

デフォルト:なし

スクリプトファイル名。スクリプトファイルは`conf/`ディレクトリに配置する必要があります。 1つ以上の「スクリプト」パラメータを指定できます。複数のスクリプトは、指定された順序で実行されます。

エンジン

オプション

デフォルト:なし

使用するスクリプトエンジンをオプションで指定します。これは、スクリプトファイルの拡張子がスクリプトエンジンへの標準マッピングではない場合にのみ必要です。たとえば、スクリプトファイルがJavaScriptでコード化されているが、ファイル名が`update-script.foo`と呼ばれている場合は、エンジン名として`javascript`を使用します。

パラメータ

オプション

デフォルト:なし

スクリプト実行コンテキストに渡されるオプションのパラメータ。これは、ネストされた型付きパラメータを持つ名前付きリスト(`<lst>`)構造として指定されます。指定されている場合、スクリプトコンテキストは「params」オブジェクトを取得します。そうでない場合、「params」オブジェクトは使用できません。

スクリプト実行コンテキスト

すべてのスクリプトには、いくつかの変数が提供されます。

logger

ロガー (org.slf4j.Logger) インスタンス。これは、スクリプトから情報をログ出力するのに役立ちます。

req

SolrQueryRequest インスタンス。

rsp

SolrQueryResponse インスタンス。

パラメータ

設定で指定されている場合は、"params" オブジェクト。

試してみよう

"techproducts" configset の一部として、JavaScript の例 update-script.js があります。

スクリプティングを試すには、./server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml ファイルで <updateRequestProcessorChain name="script"> 設定を有効にします。その後、bin/solr start -e techproducts -Dsolr.modules=scripting を実行して Solr を起動します。

この URL は、"script" 更新チェーンの指定方法を示しています: https://127.0.0.1:8983/solr/techproducts/update?commit=true&stream.contentType=text/csv&fieldnames=id,description&stream.body=1,foo&update.chain=script これは以下のログを出力します

INFO: update-script#processAdd: id=1

Solr のログ UI で記録されたメッセージを確認できます。

processAdd() およびその他のスクリプトメソッドは、false を返すことでドキュメントのさらなる処理をスキップできます。すべてのメソッドを定義する必要がありますが、一般的には processAdd() メソッドが動作の中心となります。

JavaScript

注: solrconfig.xml を確認し、更新リクエストプロセッサの定義のコメントを外して、この機能を有効にしてください。

function processAdd(cmd) {

  doc = cmd.solrDoc;  // org.apache.solr.common.SolrInputDocument
  id = doc.getFieldValue("id");
  logger.info("update-script#processAdd: id=" + id);

// Set a field value:
//  doc.setField("foo_s", "whatever");

// Get a configuration parameter:
//  config_param = params.get('config_param');  // "params" only exists if processor configured with <lst name="params">

// Get a request parameter:
// some_param = req.getParams().get("some_param")

// Add a field of field names that match a pattern:
//   - Potentially useful to determine the fields/attributes represented in a result set, via faceting on field_name_ss
//  field_names = doc.getFieldNames().toArray();
//  for(i=0; i < field_names.length; i++) {
//    field_name = field_names[i];
//    if (/attr_.*/.test(field_name)) { doc.addField("attribute_ss", field_names[i]); }
//  }

}

function processDelete(cmd) {
  // no-op
}

function processMergeIndexes(cmd) {
  // no-op
}

function processCommit(cmd) {
  // no-op
}

function processRollback(cmd) {
  // no-op
}

function finish() {
  // no-op
}

Ruby

Ruby のサポートは、JRuby プロジェクトによって実装されています。JRuby をスクリプトエンジンとして使用するには、jruby.jar を Solr に追加します。

JRuby 更新処理スクリプトの例を次に示します(渡されるすべての変数は、$logger のように $ をプレフィックスとして付ける必要があることに注意してください)

def processAdd(cmd)
  doc = cmd.solrDoc  # org.apache.solr.common.SolrInputDocument
  id = doc.getFieldValue('id')

  $logger.info "update-script#processAdd: id=#{id}"

  doc.setField('source_s', 'ruby')

  $logger.info "update-script#processAdd: config_param=#{$params.get('config_param')}"
end

def processDelete(cmd)
  # no-op
end

def processMergeIndexes(cmd)
  # no-op
end

def processCommit(cmd)
  # no-op
end

def processRollback(cmd)
  # no-op
end

def finish()
  # no-op
end

既知の問題

JRuby では、以下のコードは期待通りに動作しません。JavaScript では正しく動作します。

#  $logger.info "update-script#processAdd: request_param=#{$req.params.get('request_param')}"
#  $rsp.add('script_processed',id)

Groovy

Groovy ディストリビューションの lib/ ディレクトリにある JAR を Solr に追加します。Groovy ディストリビューションのすべての JAR が必要なわけではありませんが、メインの groovy.jar ファイル以外にも必要です(少なくとも Groovy 2.0.6 を使用してテストした時点では)。

def processAdd(cmd) {
  doc = cmd.solrDoc  // org.apache.solr.common.SolrInputDocument
  id = doc.getFieldValue('id')

  logger.info "update-script#processAdd: id=" + id

  doc.setField('source_s', 'groovy')

  logger.info "update-script#processAdd: config_param=" + params.get('config_param')

  logger.info "update-script#processAdd: request_param=" + req.params.get('request_param')
  rsp.add('script_processed',id)
}

def processDelete(cmd) {
 //  no-op
}

def processMergeIndexes(cmd) {
 // no-op
}

def processCommit(cmd) {
 //  no-op
}

def processRollback(cmd) {
 // no-op
}

def finish() {
 // no-op
}

Python

Python のサポートは、Jython プロジェクトによって実装されています。**スタンドアロン**の jython.jar(すべての依存関係を含む JAR)を Solr に追加します。

def processAdd(cmd):
  doc = cmd.solrDoc
  id = doc.getFieldValue("id")
  logger.info("update-script#processAdd: id=" + id)

def processDelete(cmd):
    logger.info("update-script#processDelete")

def processMergeIndexes(cmd):
    logger.info("update-script#processMergeIndexes")

def processCommit(cmd):
    logger.info("update-script#processCommit")

def processRollback(cmd):
    logger.info("update-script#processRollback")

def finish():
    logger.info("update-script#finish")