LuceneのNumericUtilsで、数字でソートできるドキュメントを作る

Lucene2.9.1で試行。

今まではNumberToolsだったけど、2.9からDeprecatedになったので、数字でソートできるフィールドを作るためにNumericUtilsを使う。experimentalって書いてあるのが気になるけど、まあこれしかないし。

ポイントも今までとたいして変わらない。

  • 検索するときの値もNumericUtils#intToPrefixCodedしないといけないだろう
  • 表示するときはNumericUtils#prefixCodedToIntすれば元の値に戻る
    • けど、別のフィールドで元の値を持たせたほうがいいと思うけど
import java.io.IOException;

import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.NumericUtils;

public class NumericUtilsSample {

	public static void main(String[] args) throws Exception {

		RAMDirectory dir = new RAMDirectory();
		makeIndex(dir);

		IndexReader reader = IndexReader.open(dir, true);
		Searcher searcher = new IndexSearcher(reader);
		Query query = new MatchAllDocsQuery();
		TopDocs topDocs = searcher.search(query, null, 30, new Sort(
				new SortField("id_sort", SortField.INT)));

		System.out.println("totalhits: " + topDocs.totalHits);
		System.out.println("============================");
		System.out.println("id:name");
		ScoreDoc[] scoreDocs = topDocs.scoreDocs;
		for (int i = 0; i < scoreDocs.length; i++) {
			Document doc = searcher.doc(scoreDocs[i].doc);
			// ソート用にprefixCodeにエンコードしたので、表示用にデコードする。検索するときもエンコードして検索しないとヒットしない
			System.out.print(NumericUtils.prefixCodedToInt(doc.get("id"))
					+ " : ");
			System.out.print(doc.get("name") + ", ");
			System.out.println();
		}
	}

	private static void makeIndex(RAMDirectory dir)
			throws CorruptIndexException, LockObtainFailedException,
			IOException {
		IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(),
				true, IndexWriter.MaxFieldLength.LIMITED);

		writer.addDocument(makeDoc(1, "bob"));
		writer.addDocument(makeDoc(2, "charlie"));
		writer.addDocument(makeDoc(6, "caz"));
		writer.addDocument(makeDoc(5, "echo"));
		writer.addDocument(makeDoc(4, "turtle"));
		writer.addDocument(makeDoc(3, "zulu"));

		writer.optimize();
		writer.close();
	}

	private static Document makeDoc(int id, String... names) {
		Document doc = new Document();
		doc.add(new Field("id", NumericUtils.intToPrefixCoded(id), Store.YES,
				Index.NOT_ANALYZED));
		for (String name : names) {
			doc.add(new Field("name", name, Store.YES, Index.NOT_ANALYZED));
		}
		return doc;
	}
}


結果はこんな感じ。普通ですね。

totalhits: 6
============================
id:name
1 : bob,
2 : charlie,
3 : zulu,
4 : turtle,
5 : echo,
6 : caz,