Jakarta Luceneは完全にJavaで書かれたハイパフォーマンスな全文検索エンジンのライブラリです。Luceneは全文検索が必要なアプリケーションに適しています。特にクロスプラットフォーム性を重視する場合は有用です。Javaの検索エンジンとしては、Namazu on Java2等もありますが、Namazu on Java2はライセンスがGPLで公開されており、(GPLが悪いという訳ではありませんが...)Namazu on Java2をアプリケーションに組み込むと開発したアプリケーションにもGPLが適用されます。LuceneはApache Software Licence 2.0で配布されており、アプリケーションに組み込んでもソースコードを公開する必要はありません(もちろん公開しても構いません)。LuceneはEclipseのヘルプの検索等、身近で利用されています。Luceneの優秀さは世界中の全文検索エンジンの研究者が認めるところであり、.NET、Ruby、Python、Perl、C++等の他の言語にもポーティングされています。
Luceneの原作者であるDoug Cuttingさんは、以前はXeroxのPalo Alto 研究センター(PARC), Apple, Excite@Homeで検索エンジンを書いていました。そして、いくつかの情報検索システムに関する 論文や特許を書いています。ちなみに、Luceneは、ルシーン(Luceen)と発音します。
http://jakarta.apache.org/lucene/docs/queryparsersyntax.html
馬場 肇 さんの「日本語全文検索エンジンソフトウェアのリスト」を参照
http://www.kusastro.kyoto-u.ac.jp/~baba/wais/other-system.html#fulltext_retrieval
残念ながら、Lucene自身は日本語を正しく扱うことはできません。一見正しく動いているように見えても、一部の文字がリジェクトされ正しくインデックスが作成されません。理由はアナライザというモジュールが正しく動作しないためです。アナライザは文書から単語を切り出すのですが、英語の場合単語が空白に区切られているんで、簡単に単語を抽出することができます。例えば、"I love Lucene"という文書があった場合、簡単に"I"、"love"、"Lucene"を切り出すことができます。しかし、日本語の場合は、"私はルシーンが好きです"となってしまい、単語の区切り目を検出することが困難です。
Luceneは柔軟なプラグインアーキテクチャによって構成され、アナライザを自由にカスタマイズ可能となっています。日本語で利用できるアナライザを作成することにより、日本語で利用できるようになります。日本語で利用できるアナライザは現在の所、次の3つがあります。
日本語の分かち書きを行う手法の一つとして形態素解析があります。形態素解析は、例えば、
Luceneは優秀な全文検索エンジンです。
という文書が合った場合、
| Lucene | は | 優秀な | 全文検索 | エンジン | です |
と単語毎に区切ります。また、名詞、動詞等の品詞情報も同時に取得することができます。JapaneseAnalyzerでは、文書を単語に分割し、各単語の中で検索に重要でない単語を除いて登録します。例えば、助詞(は)や助動詞(です)等は上記の文書にとって重要でない単語なので省きます。残った単語をインデックスに登録します。
CJKAnalyzerは、中国語、日本語、韓国語に対応したアナライザです。CJKAnalyzerはbi-gramという手法を利用してCJKブロックの文書を単語に分割します。例えば、上記の例文は、
| Lucene | は優 | 優秀 | 秀な | な全 ...
のように、日本語の部分が2文字づつずらした形で単語が切り出され登録されます。CJKAnalyzerは登録するインデックスの数が多くなるので、インデックスの辞書のサイズが多くなるのと、検索時にノイズが引っ掛かり易くなるという特徴があります。また、1文字の単語で検索したい場合、検索できないという問題もあります。しかしながら、これ一つで世界中の全ての言語をサポートできるのが大きな魅力です。
NutchAnalyzerはLuceneをベースとした全文検索エンジンNutchで利用されているアナライザでuni-gramという手法を利用したアナライザです。
| Lucene | は | 優 | 秀 | な | 全 ...
と一文字づつ文字を切り出します。bi-gramと比べると一文字の単語が検索できないということはありませんが、検索結果にノイズが混じりやすくなり、インデックスのサイズも大きくなります。
さて、ではLuceneを早速使ってみましょう。 ここでは、JapaneseAnalyzerを例にLuceneの利用方法を解説します。LuceneとJapaneseAnalyzerの利用には、次のソフトウェアが必要となります。
まずは、各ソフトウェアをセットアップしていきましょう。既にご存知の方は適宜読み飛ばして下さい。
Apache Antのサイト
http://ant.apache.org/bindownload.cgi
からAntの最新版をダウンロードして適当なディレクトリに展開してインストールしてください。インストール後例えば、C:\ant-1.6.2にインストールした場合、環境変数のPATHにC:\ant-1.6.2\binを追加して下さい。
Java.NETのSenのプロジェクト
https://sen.dev.java.net/servlets/ProjectDocumentList?folderID=755&expandFolder=755&folderID=0
からsenをダウンロード、適当なディレクトリで解凍(例えばc:\)し、dicディレクトリで次のようにして辞書を作成します。なお、辞書の作成にはperlが必要なので、Windows環境ではcygwinもしくはActivePerlをインストールしておいて下さい。
c:\sen-1.0\dic> ant -Dperl.bin=c:/cygwin/bin/perl.exe
辞書は、NAISTで配布しているIPADICを利用します。上記コマンドにより自動的にIPADICをダウンロードしSen用の辞書を作成します。
上記のJava.NETのSenのプロジェクトからlucene-jaをダウンロードし、解凍します。lucene-javaには、Luceneが含まれているため、本家のLuceneをダウンロードする必要はありません。
LuceneにはファイルとHTMLからインデックスの生成と検索をデモプログラムが含まれています。ここでは、デモプログラムの利用方法を説明します。
全てインストールが完了したら、環境変数の設定を行います。
C:\> SET SEN_HOME=C:\sen-1.0 C:\> SET LUCENE_HOME=C:\lucene-ja-1.4 C:\> SET PATH=%PATH%;%LUCENE_HOME%\bin
Luceneを使って検索するには、まずはインデックスに検索対象にしたいコンテンツを 登録します。インデックスの生成には、mktextndex.batもしくはmkhtmlindex.batを利用します。mktextindex.batはテキストファイルからインデックスを作成します。mkhtmlindexはご想像の通りHTMLファイルからインデックスを作成します。オプションは次の通りです([]内のオプションは省略可能)。
mkhtmlindex.bat [-create] -index <インデックスのディレクトリ> <コンテンツのディレクトリ/ファイル>
インデックスのディレクトリにディレクトリもしくはファイルで指定したコンテンツ のインデックスが生成されます。-creataは新規にインデックスを作成するときだけ利用して下さい。一度作成したインデックスには、後からコンテンツを追加することができます。
検索するには、search.batにインデックスのディレクトリを指定して実行します。
search.bat <インデックスのディレクトリ>
はっきりいって、付属のデモツールでできることは大したことはありません。Luceneの凄い所は、検索サービスを作成するために検索エンジンのプリミティブなAPIを提供しているところです。lucene-jaのorg.apache.lucene.demoパッケージにデモプログラムが入っていますので、そちらも参考にして下さい。
インデックスを作成するには、下記の手順で行います。
下記の処理を各文書毎に繰り返す
さて、では実際にコードみながら、上記の処理をみていきましょう。
インデクサの作成は、IndexWriterインスタンスの作成によって行います。
public IndexWriter IndexWriter(String index,Analyzer analyzer, boolean create)
例えば、
System.property("sen.home", "C:/sen-1.0"); IndexWriter writer = new IndexWriter("C:/home/okamoto/index", new JapaneseAnalyzer(), true);
のように指定すると、/home/okamoto/indexに新規にインデックスを作成します。なお、JapaneseAnalyzerを利用する場合は、システムプロパティのsen.homeにSenをインストールしたディレクトリを指定して下さい。
List list = .. String[] files = new File("c:\html").list(); for (int i = 0; i < files.length; i++) { list.add(new File(files)); }
File f = new File("hoge.html"); Reader reader = new BufferedReader( new InputStreamReader( new FileInputStream(file),"Windows-31J)); Document doc = new Document(); // path属性にパス名を設定 doc.add(Field.Text("path", f.getPath())); // modified属性にファイルの最新の更新時刻を設定 doc.add(Field.Keyword("modified", DateField.timeToString(f.lastModified()) ) ); // charset属性にキャラクタセットを設定 doc.add(Field.Text("charset", charset)); // contents属性にドキュメント本体のストリームを設定 doc.add(Field.Text("contents", reader)); // ドキュメントの書き込み writer.addDocument(doc);
ここでは、フィルタによって抽出したテキスト文書を検索エンジンのインデックスに登録します。
全てのドキュメントの登録が修了したらインデクサをクローズします。クローズするときは、インデクサの最適化を行ってからクローズします。
writer.optimize(); writer.close();
インデックスを作成したら、次のようにして検索を実行します。
//初期化処理 System.setProperty("sen.home",...); Searcher searcher = new IndexSearcher("C:/home/okamoto/index"); Analyzer analyzer = new JapaneseAnalyzer(); String q = "検索キーワード"; //クエリ生成 Query query = QueryParser.parse(q, "contents", analyzer); // 検索実行&結果取得 Hits hits = searcher.search(query); for (int i = 0; i < hits.length(); i++) { // i番目にヒットした文書を取得 Document doc = hits.doc(i); // 文書登録で設定した属性を取得 String path = doc.get("path"); String charset = doc.get("charset"); }
LuceneにPDF/Word/HTML用のフィルタとクローラを追加し、簡単に検索サービスを提供できるようにしたのがNutchです。Nutchは、Google等の大規模な検索エンジンと同様に分散アーキテクチャを採用しており、毎月1億ページ以上のページをインデックスに追加でき、1秒間に1000件以上の検索性能を得ることができると言われています。
Senでは、奈良先端技術大学のIPADICを形態素解析用の辞書として利用しています。辞書をカスタマイズされたい方は、IPADICのマニュアル http://chasen.aist-nara.ac.jp/stable/doc/ をご覧ください。
コメントなどありましたらお願いします。