波打際のブログさん

主に、プログラミング備忘録など。

Apache Solr でデータインポートハンドラを使ってMySQLと同期する。

はじめに

 Apache Solrを初めて使用したので備忘録です。Apache Solrを設定し、検索用のデータをMySQLと同期する方法を紹介します。

Apache Solrとは

 Apache Solr(ソーラ)とは、オープンソース検索エンジンです。これで具体的に何をしたいかというと、外部のシステムから、

http://localhost/solr/select?q=ほげほげ

こんな感じでSolrへクエリを投げて、その検索結果外部システムが受け取って使うということを実現したいのです。

環境

準備

必要なファイルのダウンロード

Apache Solr本体

 Apache Solrの本体を公式サイトからダウンロードして解凍します。今回は 3.6.2 を使用します。
Apache Lucene - Apache Solr

$ wget http://ftp.kddilabs.jp/infosystems/apache/lucene/solr/3.6.2/apache-solr-3.6.2.tgz
$ tar -zxvf apache-solr-3.6.2.tgz
MySQLJDBCドライバ

 同様にMySQLJDBCドライバもダウンロードして解凍します。
MySQL :: MySQL Community Downloads

$ wget http://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.25.tar.gz/from/http://cdn.mysql.com/
$ tar -zxvf mysql-connector-java-5.1.25.tar.gz.tgz

データベースの準備

 検索対象のデータを格納するデータベースとテーブルを構築します。

mysql> create database nyaruko;
mysql> create table bbs (id int not null auto_increment, name varchar(32), body varchar(1024), updated timestamp not null default current_timestamp on update current_timestamp, primary key (id));
 
mysql> insert into bbs (name, body) values ('ニャルラトホテプ', 'いつもニコニコあなたの隣に這い寄る混沌、ニャルラトホテプ、です!');
mysql> insert into bbs (name, body) values ('クトゥグア', 'お爺ちゃんが言ってた。ニャルラトホテプを愛するクトゥグアがいてもいい。自由とはそういうものだって。');
 
mysql> create user 'solr@localhost' identified BY 'password';
mysql> revoke all privileges on *.* from solr;
mysql> grant all on nyaruko.* to solr;

 テーブルbbsのidはautoincrementによる自動割り当て、updateも生成時に自動で値がセットされるようにします。また、solrからデータベースを操作するためのユーザを作成し、権限を設定します。

exampleをコピー

 0からSolrを設定するには、とてつもなく時間がかかりそうなので、今回は先ほど解凍した apache-solr-3.6.2 の中の examples をコピーしてそれをベースに編集していきます。(本番開発でもexampleをベースに編集していくスタイルでいいのでしょうか?疑問です。)

$ cp example/ ~/solrtest

 ホームディレクトリ直下に solrtest にリネームして配置しています。今後の説明はこの ~/solrtest を前提に行います。

ライブラリのコピー

 先ほどダウンロードした mysql-connector-java-5.1.25 と、apache-solr-3.6.2 に同梱されている、データインポートハンドラに必要なライブラリをコピーします。

$ cp -r dist/ ~/solrtest
$ cp -r contrib/ ~/solrtest
 
$ cp mysql-connector-java-5.1.25-bin.jar ~/solrtest/lib

Solrの設定ファイル構成

 Apache Solrの設定ファイルは、主に次の3つです。

solr.xml (solr/solr.xml)

 Solrのコア関連の設定を記述します。

schema.xml (solr/conf/schema.xml)

 Solrで取り扱うデータの定義を記述します。

solrconfig.xml (solr/conf/solrconfig.xml)

 Solrで読み込むライブラリや、Solrの構成を記述します。

設定

solr.xmlの設定

 solr/solr.xmlの設定を変更します。行末にあるコア名をアプリケーションに合わせた任意の名前に変更します。(変更しなくとも動きます。)

<cores adminPath="/admin/cores" defaultCoreName="UchuCQC">
  <core name="UchuCQC" instanceDir="." />
</cores>

schema.xmlの設定

 検索に使用するデータを solr/conf/schema.xmlで定義します。既存のものは記述量が多くて読みにくいので、新しく作りなおしています。

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="ニャルラトホテプ" version="1.4">
 
<types>
  <fieldType name="long" class="solr.LongField" omitNorms="true" />
  <fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true" />
  <fieldType name="timestamp" class="solr.TrieDateField" />
  <fieldType name="text_cjk" class="solr.TextField">
    <analyzer class="org.apache.lucene.analysis.cjk.CJKAnalyzer" />
  </fieldType>
  <fieldType name="text_ja" class="solr.TextField">
      <analyzer> 
        <tokenizer class="solr.JapaneseTokenizerFactory" mode="search"/>
        <filter class="solr.JapaneseBaseFormFilterFactory"/>
        <filter class="solr.JapanesePartOfSpeechStopFilterFactory" tags="lang/stoptags_ja.txt" enablePositionIncrements="true"/>
        <filter class="solr.CJKWidthFilterFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ja.txt" enablePositionIncrements="true" />
        <filter class="solr.JapaneseKatakanaStemFilterFactory" minimumLength="4"/>
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>  
  </fieldType>
</types>
 
<fields>
  <field name="id" type="long" indexed="true" stored="true" required="true" />
  <field name="name" type="text_ja" indexed="true" stored="true" termVectors="true" termPositions="true" />
  <field name="body" type="text_cjk" indexed="true" stored="true" termVectors="true" termPositions="true" />
  <field name="updated" type="timestamp" indexed="true" stored="true" termVectors="true" termPositions="true" />
</fields>
 
<uniqueKey>id</uniqueKey>
<defaultSearchField>body</defaultSearchField>
<solrQueryParser defaultOperator="AND" />
 
</schema>
  • types

 types エレメントに囲まれたブロックはフィールド内で使用するデータ型を定義しています。text_cjk型は形態素解析をする文字列型、text_ja型はN-gram解析をする文字列型となります。


  • fields

 fields エレメントに囲まれたブロックはフィールド定義になります。定義したいフィールド名と、そのフィールドの型として types で定義した型を設定します。

solrconfig.xmlの設定

インポートするライブラリの設定

 solr/conf/solrconfig.xml の80行目付近に、JDBCドライバーを読み込む設定を追記します。また、データインポートハンドラのライブラリの位置を、コピーしたディレクトリに合わせて修正しています。

<lib dir="../lib/" regex="mysql-connector-java-\d.*\.jar" />
  
 
<lib dir="../dist/" regex="apache-solr-dataimporthandler-\d.*\.jar" />
<lib dir="../contrib/dataimporthandler/lib/" regex=".*\.jar" />
検索設定の修正

 フィールドの種類を指定せずにクエリを投げた場合の、デフォルトの検索フィールドを設定します。730行目付近のtextをbodyに修正します。

<lst name="defaults">
  <str name="echoParams">explicit</str>
  <int name="rows">10</int>
  <str name="df">body</str>
</lst>
データインポートハンドラの定義

 ファイルの末尾(と言っても configure エレメント内)にデータインポートハンドラの定義を追記します。データインポートハンドラ名と、設定ファイルの場所を指定します。

<requestHandler name="/dataimport-nyarukobbs" class="org.apache.solr.handler.dataimport.DataImportHandler">
  <lst name="defaults">
    <str name="config">nyarukobbs-data-import.xml</str>
  </lst>
</requestHandler>

データインポートハンドラ(nyarukobbs-data-import.xml)の設定

 データインポートハンドラの設定ファイル solr/conf/nyarukobbs-data-import.xml を作成します。

<dataConfig>
  <dataSource name="ratings" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/nyaruko" user="solr" password="password" />
 
  <document>
    <entity name="bbs"
     query="select * from bbs"
     deltaQuery="select id from bbs where updated >= '${dataimporter.last_index_time}'"
     deltaImportQuery="select * from bbs where id=${dataimporter.delta.id}">
      <field column="id" name="id" />
      <field column="title" name="title" />
      <field column="body" name="body" />
      <field column="updated" name="updated" />
    </entity>
  </document>
  
</dataConfig>
dataSourceエレメント

 dataSourceエレメントでは、属性値としてJDBCドライバやMySQLに接続するための設定を記述しています。

entityエレメント

 entity エレメントでは、インポートに使用するSQL文とパーサーを定義しています。entityの属性値として、query、 deltaQuery、 deltaImportQuery と、3つのSQL文を定義しています。

  • query

 全てのデータをインポートする時に実行するSQL文を記述します。

select * from bbs

  • deltaQuery

 差分インポート時に、インポート対象のデータを選択するSQL文を記述します。dataimporter.last_index_timeには、solrがデータベースに最終アクセスした時間が格納されているので、${dataimporter.last_index_time}で最終アクセス日時をSQL文に埋め込むことができます。

select id from bbs where updated >= '${dataimporter.last_index_time}'
  • deltaImportQuery

 差分インポート時に、deltaQueryにより選出されたデータに基づき、インポートするデータを選択するSQL文を記述します。deltaQueryの実行結果が、dataimporter.deltaに格納されています。

select * from bbs where id=${dataimporter.delta.id}"
  • パーサー

 entityエレメント内のブロックではパーサーの定義を行なっています。インポート時に実行されるSQLクエリの結果と、schema.xmlで定義したフィールドがどのように一致するのかを指定します。fieldエレメントの属性として、columnはSQL側の列名、nameはschema.xmlで定義したフィールド名を指定します。

確認

起動

アプリケーションのディレクトリ(今回は、solrtest)に移動して、下記コマンドを実行します。

$ java -jar start.java

起動確認

http://localhost:[ポート番号]/solr/admin/dataimport.jsp

 にアクセスし、定義したデータインポートハンドラ(dataimport-nyarukobbs)が表示されていれば構文にエラーはない状態です。500が表示された場合は設定に誤りがあるので、修正が必要です。(ポート番号は起動時に表示されるポート番号です。 )

データのインポート

 dataimport-nyarukobbs をクリックし、管理パネルを開きます。管理パネルのFull-Importではデーターベースをすべてインポートし、Delta-Importは差分をインポートします。まずは、Full-Import を試してみてください。(クリックしてすぐには反映されないので、数分待つ必要があります。作業状況はStatusから確認ができます。)

正常にインポートされれば

http://localhost:[ポート番号]/solr/admin/

からデータを検索できます。

差分データのインポート

 Delta-Importが正常に動作することを確認するためには、MySQLのnyarukoデーターベースで、

mysql> insert into bbs (name, body) values ('ハスター', 'えっと、僕にも真尋君ニウムが作れないかなって。');

といったSQL文を実行してデータを追加し、Delta-Importを実行します。

追記

2014年7月4日

 id:sisidovskiさんにschema.xmlの誤りを教えていただき修正しました。ありがとうございます。

参考サイト

Solr Tutorial