Lucene 2.4とLucene 2.0のインデックス構築速度比較

Luceneは、こちらのベンチマークなどを見る限り、Sennaなど他の全文検索エンジンに比べて相当遅いとされているようです。

上記ページのベンチマークではLucene 2.0が使われています。僕も数年前にLucene 2.0を使ったことがあって、それ以降はLuceneに触れていなかったんですが、最近のバージョンはパフォーマンスが大幅に改善されているそうなので、どれくらい速くなったのか、インデックス作成速度を比較してみました。

比較に使ったのはLucene 2.4.1(2009/03)とLucene 2.0.0(2006/05)です。以下の条件でインデックス作成時間を計測しました。

  • データ: 日本語版Wikipediaのダンプから先頭20万記事
  • インデックス形式:
    • 記事タイトル: Store.YES, Index.ANALYZED(元文字列+インデックス)
    • 記事本文: Store.COMPRESS, Index.ANALYZED(圧縮元文章+インデックス)
  • アナライザ: CJKAnalyzer(bi-gram)
  • バッファサイズ: setMaxBufferedDocs(10000)

自分の環境では、以下の結果が出ました。

バージョン Lucene 2.4.1 Lucene 2.0.0
インデックス構築時間 377秒 994秒
処理記事数(1秒あたり) 530.5 201.2
インデックスサイズ 1.04GB 0.97GB

Lucene 2.4.1の方が2.6倍も速いという驚きの結果になりました。最近のLuceneはすごく頑張ってるということが分かりました。

検証に使ったプログラムは以下の通りです(Lucene 2.4.1用なので、2.0.0に対応させるには若干修正が必要)。

public class LuceneBenchmark {
    public static void main(String[] args) throws Exception {
        File dataFile = new File("C:/data/jawiki-20090124-pages-articles.xml");
        File indexDir = new File("C:/data/index");
        if (indexDir.exists()) {
            FileUtils.deleteDirectory(indexDir);
        }

        Analyzer analyzer = new CJKAnalyzer();
        IndexWriter indexWriter = new IndexWriter(indexDir, analyzer,
                MaxFieldLength.UNLIMITED);
        indexWriter.setMaxBufferedDocs(10000);

        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader xmlReader = factory
                .createXMLStreamReader(new FileInputStream(dataFile));

        String title = null;
        int indexSize = 0;

        long start = System.currentTimeMillis();

        for (; xmlReader.hasNext(); xmlReader.next()) {
            if (!xmlReader.isStartElement()) {
                continue;
            }
            String elemName = xmlReader.getName().getLocalPart();
            if (elemName.equals("title")) {
                title = xmlReader.getElementText();
            } else if (elemName.equals("text")) {
                String body = xmlReader.getElementText();

                Document doc = new Document();
                doc.add(new Field("title", title, Store.YES, Index.ANALYZED));
                doc.add(new Field("body", body, Store.COMPRESS, Index.ANALYZED));
                indexWriter.addDocument(doc);

                indexSize++;
                if (indexSize % 500 == 0) {
                    System.out.println(indexSize);
                    if (indexSize >= 200000) {
                        break;
                    }
                }
            }
        }

        xmlReader.close();
        indexWriter.close();

        long elapsed = System.currentTimeMillis() - start;
        System.out.println((elapsed / 1000) + " sec.");
    }
}