第4回 Solr4にRDBのデータをくわせる

2013-12-04

Solr4を動かしてみるシリーズの4回目です。

今回は、SolrにRDBのデータをくわせてみます。

solrのチュートリアルにはRESTインターフェイスからインデックスするデータを登録するやり方が書いてありますが、インデックスしたいデータの多くはRDBやNoSQL等のストレージに格納されていることが多いと思います。
いっこいっこPOSTなんてやってられません。
で、RDBのデータを読んでインデックスを作成することにします。

このチュートリアルではRDBとしてMySQLを使用します。

4.1. JDBCドライバを設置する

solrはjava製のプロダクトなので、MySQLに接続するためにJDBCドライバを使います。
MySQLのサイトからJDBCドライバをダウンロードします。

MySQL Connector/J

解凍してjarをコアディレクトリのlib内に置きます。

tar zxvf mysql-connector-java-5.1.27.tar.gz
cp ./mysql-connector-java-5.1.27/mysql-connector-java-5.1.27-bin.jar /opt/solr/server/core0/lib/

4.2. データインポート設定ファイルを作成する

RDBからデータをインポートする際の設定ファイルを作成します。
confにsolr-data-config.xmlとしてxmlファイルを作成します。

<dataConfig>
  <document name="books">
    <entity name="book" pk="book_id"
               query="SELECT book_id, title, description FROM books WHERE delete_flag = false"
               deltaImportQuery="SELECT book_id, title, description FROM books WHERE book_id = '${dataimporter.delta.book_id}' AND delete_flag = false"
               deltaQuery="SELECT book_id FROM books WHERE update_at &gt; '${dataimporter.last_index_time}' AND delete_flag = false"
               deletedPkQuery="SELECT book_id FROM books WHERE delete_flag = true" >
      <field column="book_id" name="id" />
      <field column="title" name="title" />
      <field column="description" name="description" />
    </entity>
  </document>
</dataConfig>

4.3. プロパティファイルにデータソースの設定を記述する

conf/properties/solr.propertiesを編集します。

vi /opt/solr/server/solr/core0/conf/properties/solr.properties
~
dataimport.datasource.driver:com.mysql.jdbc.Driver
dataimport.datasource.url:jdbc:mysql://xx.xx.xx.xx:3306/<db_name>
dataimport.datasource.user:<user_name>
dataimport.datasource.password:<passwd>
dataimport.datasource.useUnicode:true
dataimport.datasource.characterEncoding:utf8
dataimport.datasource.useOldUTF8Behavior:true
~

4.4. データインポートハンドラを追加する

データインポートハンドラを追加するにはconf/solrconfig.xmlを編集します。

<lib dir="../../../contrib/dataimporthandler/lib/" regex=".*\.jar" />
<lib dir="../../../dist/" regex="solr-dataimporthandler-.*\.jar" />

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
    <lst name="defaults">
        <str name="config">solr-data-config.xml</str>
        <lst name="datasource">
            <str name="driver">${dataimport.datasource.driver:com.mysql.jdbc.Driver}</str>
            <str name="url">${dataimport.datasource.url}</str>
            <str name="user">${dataimport.datasource.user}</str>
            <str name="password">${dataimport.datasource.password}</str>
            <str name="useUnicode">${dataimport.datasource.useUnicode:true}</str>
            <str name="characterEncoding">${dataimport.datasource.characterEncoding:utf8}</str>
            <str name="useOldUTF8Behavior">${dataimport.datasource.useOldUTF8Behavior:true}</str>
        </lst>
    </lst>
  </requestHandler>

4.5. 管理画面からデータインポートを実行してみる

ブラウザから
http://xx.xx.xx.xx:8983/solr/#/core0/dataimport/
へアクセスします。

dataimport

executeボタンをクリックすればデータのインポートが始まります。

補足

MySQLから大量データの読み込みを行うと、
OutOfMemory ExceptionやsetFetchSizeのExceptionなどの、もうお手上げになりそうなエラーがでます。
そんなときは、solrconfig.xmldatasource
-1
を指定してみてください。

参考:
Solr Wiki – Data Import Request Handler

注釈

少し前に、

「DBからデータを読み取ってsolrにくわせるのと、DBとsolrに同時POSTするのと何が違うのか?結果は同じじゃないか」
という質問を頂きました。

おかげで上記2つの相違について考えるきっかけとなったので注釈として記したいと思います。
何が違うのか・・・その答えの1つがACID属性と二相コミットです。

  1. DBからデータを読み取ってsolrにくわせる
  2. DBとsolrに同時POSTする

1.のケースは当然、DBにデータが格納されてからsolrがインデックスを作成するため、
データの登録からインデックス作成の間に若干の遅延が生じます。
しかし、DBに永続化されたデータからインデックスを作成するため、DB内のデータとインデックスとの間に差異が生じる可能性は著しく低いです。
もし、差異が生じてしまったら、DBのデータから再度インデックスを生成し直せばよいのです。

2.のケースはDBとsolrに同時にデータ登録を行うため、遅延が生じにくくあります。
しかし、DBへの登録とsolrへの登録、どちらかが失敗するケースを考慮する必要があります。
DBへの登録とsolrへの登録、どちらとも成功した場合のみ変更をコミットするのか?(二相コミットですね。)
どちらかが失敗した場合、ロールバックするのか?また、ロールバックできるのか?
といったことを考慮する必要があります。
DBとsolr、どちらもがACID属性を備えていたとしても、2者間のACIDは保証されません。
故にアプリケーションで補足する必要があります。

1.の方法を採用するか、2.の方法を採用するかはアプリケーション及びデータの特性によって決定すべきで、一概にどちらがよいというものではありません。

良い選択を!

第5回 Solr4でレプリケーションを構築する