Apache Solr でデータインポートハンドラを使ってMySQLと同期する。
はじめに
Apache Solrを初めて使用したので備忘録です。Apache Solrを設定し、検索用のデータをMySQLと同期する方法を紹介します。
Apache Solrとは
Apache Solr(ソーラ)とは、オープンソースの検索エンジンです。これで具体的に何をしたいかというと、外部のシステムから、
http://localhost/solr/select?q=ほげほげ
こんな感じでSolrへクエリを投げて、その検索結果外部システムが受け取って使うということを実現したいのです。
環境
- Apache Solr 3.6.2
準備
必要なファイルのダウンロード
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
MySQLのJDBCドライバ
同様にMySQLのJDBCドライバもダウンロードして解凍します。
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 を前提に行います。
Solrの設定ファイル構成
Apache Solrの設定ファイルは、主に次の3つです。
設定
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>
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/
からデータを検索できます。
追記
2014年7月4日
id:sisidovskiさんにschema.xmlの誤りを教えていただき修正しました。ありがとうございます。