INFORMATION
テクノロジ

ScriptUpdateProcessorの手軽な利用

阿部 慎一朗 著

はじめに

SolrのScriptUpdateProcessorを、サンプルコードを動かしながら紹介します。

ScriptUpdateProcessor とは?

Solr 4 から、インデクシングの前処理を行うUpdateRequestProcessorに、ScriptUpdateProcessorが追加されています。ScriptUpdateProcessorは、JVMがサポートするスクリプト言語(JavaScriptやJRubyなど)を使用して、事前コンパイルなしでスクリプトを実行し、ドキュメント登録時にインデクシングの前処理するというUpdateRequestProcessorです。

参考JIRASOLR-1725
参考Solr Wikihttp://wiki.apache.org/solr/ScriptUpdateProcessor

これまではインデクシングの前処理を行うのに、JavaでUpdateRequestProcessorをextendsしてコードを書く必要がありました。しかし、ScriptUpdateProcessorが追加されたことにより、JavaScriptなどで手軽にコードを書いてすぐに実行することが実現できます。

ScriptUpdateProcessorでは、JavaのScriptEngineを使って、$SOLR_HOME/confに配置したスクリプトを解析し、インデクシング時に処理を行っています。($SOLR_HOMEはSolrホームディレクトリです。)

インデクシングの前処理の例

インデクシングの前処理が必要なケースはいろいろあります。

  • 任意のフィールドからファイル名を抽出したい。(ファイル名検索に利用)
  • 任意のフィールドから任意の文字列を抽出してタグ付けしたい。(タグ検索やファセット絞込検索に利用)
  • 任意のフィールドから任意の文字列を抽出してグループ分けしたい。(グループ化検索に利用)
  • 任意のフィールドの値をURLデコードしたい。

たとえば、ManifoldCFを利用してWebサーバをクロールしている場合があります。ManifoldCFはWebスパイダ機能を備えていますから、htmlのリンクをたどって別のhtmlやリンクドキュメント(pdfやxlsなど)を探します。発見されたドキュメントは、Solrへポストされ、Solrにて、htmlファイルやバイナリファイルのテキスト抽出が行われ、インデックスに登録されます。

インデックスに登録される情報は主なものとして、id(クロールしたURLがセットされます)、title(htmlやバイナリファイルから抽出されたtitleメタデータ)、author(htmlやバイナリファイルから抽出されたauthorメタデータ)、content(テキスト抽出されたコンテンツ)があります。

このとき、インデックスに登録される情報に、ファイル名があれば、ファイル名検索ができるのですが、ManifoldCFのWebコネクタでは、ファイル名取得ができません(ManifoldCF 1.3現在)。 こういうケースで、インデクシングの前処理が必要になってきます。ファイル名のフィールドを用意して、URL情報からファイル名の文字列を取得してインデックスに登録したいという要件があります。

今回、この要件をみたすScriptUpdateProcessor利用例をご紹介します。

ScriptUpdateProcessor利用例

ScriptUpdateProcessorを利用する設定方法をご説明します。

まず、solrconfig.xmlで、updateRequestProcessorChainを定義します。

    <updateRequestProcessorChain name="script">
      <processor class="solr.StatelessScriptUpdateProcessorFactory">
        <str name="script">update-script.js</str>
      </processor>
      <processor class="solr.LogUpdateProcessorFactory" />
      <processor class="solr.RunUpdateProcessorFactory" />
    </updateRequestProcessorChain>

チェインの中に、StatelessScriptUpdateProcessorFactoryを定義して、scriptパラメータにスクリプトを定義します。

Statelessという名前がついていますが、これは更新リクエスト時に、毎回スクリプトが評価されるのでこのような名称がつけられています。今のところ、スクリプトをキャッシュしたりコンパイルしたりするScriptUpdateProcessorは実装されていません。スクリプトはいつでも編集できるようになっており、Solrのリロードをする必要がありません。一方で、更新リクエストのたびにスクリプトが評価されるので、その分インデクシング時のパフォーマンスが落ちるという欠点はあります。

続いて、このチェイン(チェイン名=script)を、更新ハンドラで呼び出すように設定します。

    <requestHandler name="/update" class="solr.UpdateRequestHandler">    
      <lst name="defaults">
        <str name="update.chain">script</str>
      </lst>       
    </requestHandler>

チェインはさまざまな更新ハンドラで呼び出すように設定できます。バイナリファイルのインデクシングで使うExtractingRequestHandlerや、RDBなどからデータをインポートするDataImportHandlerなどの更新ハンドラでも、チェインを設定できます。

そして、スクリプトを編集します。$SOLR_HOME/confに、あらかじめupdate-script.jsが配置されています。 これを編集します。スクリプト内のprocessAdd()メソッドを編集します。

function processAdd(cmd) {

  doc = cmd.solrDoc;
  id = doc.getFieldValue("id");

  var paths = new Array();
  var file = "";
  var decodedId = decodeURI(id);
  paths = decodedId.split('/');
  file = paths[paths.length - 1];

  var extensionArray = ['json','docx','pptx','xlsx','html','xml','csv','pdf','doc','ppt','xls','odt','odp','ods','ott','otp','ots','rtf','htm','txt','log'];
  
  var isInsert = new Boolean(false);
  for(i = 0; i < extensionArray.length; i++) {
    var ext = "." + extensionArray&#91;i&#93;;
    if (file.indexOf(ext) != -1) {
      isInsert = true;     
      file = file.substring(0, file.indexOf(ext) + ext.length);
      logger.info("file:" + file);
      break;
    }
  }
  
  if (isInsert == true){
    doc.setField("filename_s", file);
  }
}
&#91;/plain&#93;

<p>
上記のサンプルコードは、URLがフィールド値となるidフィールドを取得して、そのURLから拡張子を判別してファイル名を取得するコードとなります。ファイル名が見つかったら、filename_sフィールドに値をセットしています。このサンプルコードは、ManifoldCFでWebクロールした際に、リンクドキュメントを得て、このURLからファイル名を抽出するということを実現したものになります。
</p>

<p>
そしてドキュメントを登録します。今回の例ではManifoldCFからWebクロールします。
</p>

<p>
ドキュメント登録後、検索結果は次のようになります。
</p>
<p>検索リクエスト</p>
[plain]
http://localhost:8983/solr/select?q=*:*&fl=id,filename_s

検索結果レスポンス

<response>
  <lst name="responseHeader">…</lst>
  <result name="response" numFound="7" start="0">
    <doc>
      <str name="id">http://server/rondhuit</str>
    </doc>
    <doc>
      <str name="id">http://server/rondhuit/aaa.pdf</str>
      <str name="filename_s">aaa.pdf</str>
    </doc>
    <doc>
      <str name="id">http://server/rondhuit/ABC%E3%81%84%E3%82%8D%E3%81%AF.doc</str>
      <str name="filename_s">ABCいろは.doc</str>
    </doc>
    <doc>
      <str name="id">http://server/rondhuit/ABC%E3%81%84%E3%82%8D%E3%81%AF.xls</str>
      <str name="filename_s">ABCいろは.xls</str>
    </doc>
    <doc>
      <str name="id">http://server/rondhuit/ABC%E3%81%84%E3%82%8D%E3%81%AF.pptx</str>
      <str name="filename_s">ABCいろは.pptx</str>
    </doc>
    <doc>
      <str name="id">http://server/rondhuit/?id=475</str>
    </doc>
    <doc>
      <str name="id">http://server/rondhuit/test.html?id=1</str>
      <str name="filename_s">test.html</str>
    </doc>
  </result>
</response>

このようにして、スクリプトを編集することで、さまざまなインデクシングの前処理を実現できます。

まとめ

以上ScriptUpdateProcessorについて、設定やサンプルコードを通じて簡単にご説明しました。スクリプトを加工して手軽に前処理を記述できるUpdateRequestProcessorは非常に有意義なものと思われます。何かしら前処理に関する必要性が生じたときは、このUpdateRequestProcessorの利用をご検討ください。



KandaSearch

KandaSearch はクラウド型企業向け検索エンジンサービスです。
オープンAPIでカスタマイズが自由にできます。

  • セマンティックサーチ

    人間が理解するように検索エンジンがテキストや画像を理解して検索できます。

  • クローラー

    検索対象文書を収集するWebクローラーが使えます。

  • 簡単操作のUIと豊富なライブラリー

    検索や辞書UIに加え、定義済み専門用語辞書/類義語辞書やプラグインがあります。

  • ローコードで低コスト導入

    検索UIで使い勝手を調整した後、Webアプリケーションを自動生成できます。

セミナー

企業が検索エンジンを選定する際のポイントから、
実際の導入デモをお客様ご自身でご体験!