Lucene 2.4とLucene 2.0の検索速度比較

前回、Lucene 2.4と2.0でインデックス構築速度の比較をしたので、ついでに検索速度の比較もしてみました。

前回のエントリーでは、以下のようにインデックスを作成しました。

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

このインデックスに対し、ランダムに選ばれた1000件の記事タイトルをクエリとして検索を行い、所要時間を計測しました(5回測定して中央値を採用)。ちなみに、初回の検索はsearcherがウォームアップされていないので、2回目以降に比べて非常に遅いです。

結果は次のようになりました。

バージョン Lucene 2.4.1 Lucene 2.0.0
検索時間 4173 ms 8793 ms

検索速度でも、Lucene 2.4がLucene 2.0を大幅に上回る結果になりました。

Lucene 2.4で使った検証用コードは以下です(2.0でも同等のコードを使用)。

public class LuceneSearchBenchmark {
    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-2.4");

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

        List<String> keywords = new ArrayList<String>(200000);
        int count = 0;
        for (; xmlReader.hasNext(); xmlReader.next()) {
            if (!xmlReader.isStartElement()) {
                continue;
            }
            String elemName = xmlReader.getName().getLocalPart();
            if (elemName.equals("title")) {
                keywords.add(xmlReader.getElementText());
                if (++count >= 200000) {
                    break;
                }
            }
        }
        Collections.shuffle(keywords);

        xmlReader.close();

        IndexSearcher searcher = new IndexSearcher(indexDir.getPath());
        Analyzer analyzer = new CJKAnalyzer();

        List<Integer> result = new ArrayList<Integer>();
        int trialCount = 5;
        for (int n = 1; n <= trialCount; n++) {
            long start = System.currentTimeMillis();

            for (int i = 0; i < 1000; i++) {
                PhraseQuery phrase = new PhraseQuery();
                TokenStream stream = analyzer.reusableTokenStream("body",
                        new StringReader(keywords.get(i)));
                Token token = new Token();
                while ((token = stream.next(token)) != null) {
                    phrase.add(new Term("body", token.term()));
                }

                searcher.search(phrase, 100);

                if (i % 100 == 0) {
                    System.out.println(i);
                }
            }

            long elapsed = System.currentTimeMillis() - start;
            result.add((int) elapsed);

            System.out.println(n + ": " + elapsed + " ms.");
        }

        Collections.sort(result);

        int finalResult = result.get(trialCount / 2);
        System.out.println("final result: " + finalResult + " ms.");
    }
}