<< 2011/04/04 | Home | 2011/04/06 >>

Lucene3.1 メモその5 - 数値型のフィールドを設定する

基本その5,数値型フィールドの保存

Luceneのインデックスは基本的にStringかbyte[]のみを保存するようになっているようです。数値型を保存する場合、String.valueOf(number)で文字列に変換して保存してもいいですが、辞書順にソートすると 1,10,11,2,3,4...などと人間味のない順番になってしまう可能性があります。
そこで数値型を保存する場合はNumericFieldというクラス(Lucene2.9より導入)を使います。

サンプルプログラムでは以下のことをやっています
・メモリ上(RAMDirectory)にインデックスを格納
・それぞれ8,9,10,11の値をもつドキュメントを4つ追加
・ソートキーとなるフィールドを指定して検索
・自然な順番でソートされていることを確認

NumericUtilsというユーティリティクラスを使って数値を文字列、またはその逆に変換しても良いみたいです(NumericFieldの内部でNumericUtilsを使っている)。

    @Test
public void index() throws Exception {
RAMDirectory directory = new RAMDirectory();
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_31);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_31, analyzer);
IndexWriter writer = new IndexWriter(directory, iwc);

for (int i = 8; i < 12; i++) {
Document doc = new Document();
doc.add(new NumericField("int_field", Field.Store.YES, true).setIntValue(i));
System.out.println(doc);
writer.addDocument(doc);
}
writer.commit();

IndexReader reader = IndexReader.open(writer, true);
IndexSearcher searcher = new IndexSearcher(reader);
TopDocs td = searcher.search(new MatchAllDocsQuery()
, 1000, new Sort(new SortField("int_field", SortField.INT)));
assertThat(td.totalHits, is(4));
assertThat(searcher.doc(td.scoreDocs[0].doc).get("int_field"), equalTo("8"));
assertThat(searcher.doc(td.scoreDocs[1].doc).get("int_field"), equalTo("9"));
assertThat(searcher.doc(td.scoreDocs[2].doc).get("int_field"), equalTo("10"));
assertThat(searcher.doc(td.scoreDocs[3].doc).get("int_field"), equalTo("11"));

reader.close();
writer.close();
searcher.close();
directory.close();
}


すぐ試せるmavenベースのソースコードはここに置いてあります。
Lucene3.1、JUnit4.8を使っています。

関連記事:
Lucene/Solr 3.1 リリース | 関口宏司のLuceneブログ
Lucene3.1 メモその1 - ドキュメントのインデックスを作成して検索する - 侍ズム
Lucene3.1 メモその2 - ドキュメントを追加する - 侍ズム
Lucene3.1 メモその3 - ドキュメントを更新する - 侍ズム
Lucene3.1 メモその4 - 検索結果をソートする - 侍ズム
Lucene3.1 メモその6 - 日本語のドキュメントを検索する - 侍ズム
Lucene3.1 メモその7 - 形態素解析をして日本語のドキュメントを検索する - 侍ズム


タグ :
このエントリーをはてなブックマークに追加   

Lucene3.1 メモその4 - 検索結果をソートする

基本その4,検索結果のソート

以下のことをやります
・メモリ上(RAMDirectory)にインデックスを格納
・ドキュメントを3つ追加
・ソートキーとなるフィールドを指定して検索
・ソートキーとなるフィールドを降順で指定して検索

IndexSearcher#searchにSortFieldを渡すことで検索結果をソートできます。
デフォルトでは昇順のソートになりますが、SortFieldのコンストラクタにbooleanでtrueを渡すことで降順のソートもできます。
今回はインデックスにあるドキュメント全てを取得したかったのでMatchAllDocsQueryというクラスを使いました。特に検索条件を指定しなくてもドキュメントを取り出せるので場合によっては便利です。

    @Test
public void index() throws Exception {
RAMDirectory directory = new RAMDirectory();
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_31);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_31, analyzer);
IndexWriter writer = new IndexWriter(directory, iwc);

Document doc = new Document();
doc.add(new Field("str_field", "abc",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
Document doc2 = new Document();
doc2.add(new Field("str_field", "def",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc2);
Document doc3 = new Document();
doc3.add(new Field("str_field", "hij",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc3);
writer.commit();

IndexReader reader = IndexReader.open(writer, true);
IndexSearcher searcher = new IndexSearcher(reader);
TopDocs td = searcher.search(new MatchAllDocsQuery()
, 1000, new Sort(new SortField("str_field", SortField.STRING)));
assertThat(td.totalHits, is(3));
System.out.println(searcher.doc(td.scoreDocs[0].doc));
assertThat(searcher.doc(td.scoreDocs[0].doc).get("str_field"), equalTo("abc"));
assertThat(searcher.doc(td.scoreDocs[1].doc).get("str_field"), equalTo("def"));
assertThat(searcher.doc(td.scoreDocs[2].doc).get("str_field"), equalTo("hij"));

td = searcher.search(new MatchAllDocsQuery()
, 1000, new Sort(new SortField("str_field", SortField.STRING, true)));
assertThat(td.totalHits, is(3));
assertThat(searcher.doc(td.scoreDocs[0].doc).get("str_field"), equalTo("hij"));
assertThat(searcher.doc(td.scoreDocs[1].doc).get("str_field"), equalTo("def"));
assertThat(searcher.doc(td.scoreDocs[2].doc).get("str_field"), equalTo("abc"));

reader.close();
writer.close();
searcher.close();
directory.close();
}


すぐ試せるmavenベースのソースコードはここに置いてあります。
Lucene3.1、JUnit4.8を使っています。

関連記事:
Lucene/Solr 3.1 リリース | 関口宏司のLuceneブログ
Lucene3.1 メモその1 - ドキュメントのインデックスを作成して検索する - 侍ズム
Lucene3.1 メモその2 - ドキュメントを追加する - 侍ズム
Lucene3.1 メモその3 - ドキュメントを更新する - 侍ズム
Lucene3.1 メモその5 - 数値型のフィールドを設定する - 侍ズム
Lucene3.1 メモその6 - 日本語のドキュメントを検索する - 侍ズム
Lucene3.1 メモその7 - 形態素解析をして日本語のドキュメントを検索する - 侍ズム



タグ :
このエントリーをはてなブックマークに追加   

Lucene3.1 メモその3 - ドキュメントを更新する

基本その3,ドキュメントの更新

ドキュメントを「更新」というメソッドはなく、「削除→追加」という手順を追うことになります。
ドキュメントを更新するにはupdateDocumentというメソッドを使います。

ただ、一意性制約を付けて同じIDのドキュメントの追加を防ぐようなことはできないので、アプリケーション側で気をつけてドキュメントを更新してあげる必要があります。
今回は"ID"というフィールドを作って、IDフィールドをキーに更新してみました。

サンプルプログラムでは下のことをやっています
・メモリ上(RAMDirectory)にインデックスを格納
・英語ドキュメントを1つ追加
・IDを指定してドキュメントを更新
・当初のドキュメントがヒットしないことを確認
・更新した方のドキュメントがヒットすることを確認

    @Test
public void index() throws Exception {
RAMDirectory directory = new RAMDirectory();
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_31);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_31, analyzer);
IndexWriter writer = new IndexWriter(directory, iwc);

Document doc = new Document();
doc.add(new Field("id", "001",
Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("str_field", "quick brown fox jumped over the lazy dog.",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
writer.commit();
IndexReader reader = IndexReader.open(writer, true);
IndexSearcher searcher = new IndexSearcher(reader);
QueryParser parser = new QueryParser(Version.LUCENE_31, "str_field", analyzer);
TopDocs td = searcher.search(parser.parse("fox"), 1000);
assertThat(td.totalHits, is(1));

Document doc2 = new Document();
doc.add(new Field("id", "001",
Field.Store.YES, Field.Index.NOT_ANALYZED));
doc2.add(new Field("str_field", "quick brown fox jumped over the lazy whale.",
Field.Store.YES, Field.Index.ANALYZED));
writer.updateDocument(new Term("id", "001"),doc2);
writer.commit();

searcher.close();
reader = reader.reopen();
searcher = new IndexSearcher(reader);

td = searcher.search(parser.parse("dog"), 1000);
assertThat(td.totalHits, is(0));
td = searcher.search(parser.parse("whale"), 1000);
assertThat(td.totalHits, is(1));

writer.close();
searcher.close();
directory.close();
}


すぐ試せるmavenベースのソースコードはここに置いてあります。
Lucene3.1、JUnit4.8を使っています。

関連記事:
Lucene/Solr 3.1 リリース | 関口宏司のLuceneブログ
Lucene3.1 メモその1 - ドキュメントのインデックスを作成して検索する - 侍ズム
Lucene3.1 メモその2 - ドキュメントを追加する - 侍ズム
Lucene3.1 メモその4 - 検索結果をソートする - 侍ズム
Lucene3.1 メモその5 - 数値型のフィールドを設定する - 侍ズム
Lucene3.1 メモその6 - 日本語のドキュメントを検索する - 侍ズム
Lucene3.1 メモその7 - 形態素解析をして日本語のドキュメントを検索する - 侍ズム


タグ :
このエントリーをはてなブックマークに追加   

Lucene3.1 メモその2 - ドキュメントを追加する

基本その2,ドキュメントの追加

以下のことをやります
・メモリ上(RAMDirectory)にインデックスを格納
・英語ドキュメントを1つ追加
・検索すると1件ヒットすることを確認
・もう1つドキュメントを追加
・検索すると1件しかヒットしないことを確認
・IndexReaderをリオープンし、再度検索し、ドキュメントが2件ヒットすることを確認

つまり、IndexWriter.addDocument()/commit()してもすぐには検索可能になりません。IndexReaderを作り直すか、リオープンしてIndexSearcherを作り直すことで検索可能になります。

    @Test
public void index() throws Exception {
RAMDirectory directory = new RAMDirectory();
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_31);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_31, analyzer);
IndexWriter writer = new IndexWriter(directory, iwc);

Document doc = new Document();
doc.add(new Field("str_field", "quick brown fox jumped over the lazy dog.",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
writer.commit();
IndexReader reader = IndexReader.open(writer, true);
IndexSearcher searcher = new IndexSearcher(reader);
QueryParser parser = new QueryParser(Version.LUCENE_31, "str_field", analyzer);
TopDocs td = searcher.search(parser.parse("fox"), 1000);
assertThat(td.totalHits, is(1));

Document doc2 = new Document();
doc2.add(new Field("str_field", "quick brown dog jumped over the lazy fox.",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc2);
writer.commit();

td = searcher.search(parser.parse("fox"), 1000);
assertThat(td.totalHits, is(1));

searcher.close();
reader = reader.reopen();
searcher = new IndexSearcher(reader);

td = searcher.search(parser.parse("fox"), 1000);
assertThat(td.totalHits, is(2));

writer.close();
searcher.close();
directory.close();
}


すぐ試せるmavenベースのソースコードはここに置いてあります。
Lucene3.1、JUnit4.8を使っています。

関連記事:
Lucene/Solr 3.1 リリース | 関口宏司のLuceneブログ
Lucene3.1 メモその1 - ドキュメントのインデックスを作成して検索する - 侍ズム
Lucene3.1 メモその3 - ドキュメントを更新する - 侍ズム
Lucene3.1 メモその4 - 検索結果をソートする - 侍ズム
Lucene3.1 メモその5 - 数値型のフィールドを設定する - 侍ズム
Lucene3.1 メモその6 - 日本語のドキュメントを検索する - 侍ズム
Lucene3.1 メモその7 - 形態素解析をして日本語のドキュメントを検索する - 侍ズム


タグ :
このエントリーをはてなブックマークに追加   

Lucene3.1 メモその1 - ドキュメントのインデックスを作成して検索する

最近Luceneを触っています。
Luceneについて大抵のことはLucene入門に書いてあるけれども非推奨になっているAPIも結構あります。
そこで最新のLucene3.1で警告なしにコンパイルが通るサンプルプログラムをちょこちょこ掲載していきたいと思います。

まず最初は基本中の基本、インデックス作成と検索。
以下のことをやるプログラムです。
・メモリ上(RAMDirectory)にインデックスを格納
・英語と日本語のドキュメント2つ分のインデックスを作成
→ Document オブジェクトにaddメソッドで検索対象のフィールドを追加していく
→ Luceneにインデックスだけでなく値を保存しておきたいときはFieldのコンストラクタにField.Store.YESを指定する
→ フィールドを解析(トークナイズ)しておきたい場合はField.Index.ANALYZEDを指定する
・英単語で検索、1件ヒットする
→ IndexSearcherのsearchメソッドで検索、TopDocsオブジェクトが返る
→ TopDocsオブジェクトにはヒットしたドキュメントの件数や、ドキュメントのIDが格納されている
→ ドキュメント自体を取り出すにはIndexSearcher.doc(int)を使う

    @Test
public void index() throws Exception {
RAMDirectory directory = new RAMDirectory();
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_31);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_31, analyzer);
IndexWriter writer = new IndexWriter(directory, iwc);

Document doc = new Document();
doc.add(new Field("str_field", "quick brown fox jumped over the lazy dog.",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
Document doc2 = new Document();
doc2.add(new Field("str_field", "貴社の記者が汽車で帰社した",
Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc2);
writer.close();
IndexSearcher searcher = new IndexSearcher(directory, true);
QueryParser parser = new QueryParser(Version.LUCENE_31, "str_field", analyzer);
TopDocs td = searcher.search(parser.parse("fox"), 1000);
assertThat(td.totalHits, is(1));
Document doc3 = searcher.doc(td.scoreDocs[0].doc);
assertEquals("quick brown fox jumped over the lazy dog.", doc3.get("str_field"));
searcher.close();
directory.close();
}


すぐ試せるmavenベースになってるソースコードはここに置いてあります。
Lucene3.1、JUnit4.8を使っています。

関連記事:
Lucene/Solr 3.1 リリース | 関口宏司のLuceneブログ
Lucene3.1 メモその2 - ドキュメントを追加する - 侍ズム
Lucene3.1 メモその3 - ドキュメントを更新する - 侍ズム
Lucene3.1 メモその4 - 検索結果をソートする - 侍ズム
Lucene3.1 メモその5 - 数値型のフィールドを設定する - 侍ズム
Lucene3.1 メモその6 - 日本語のドキュメントを検索する - 侍ズム
Lucene3.1 メモその7 - 形態素解析をして日本語のドキュメントを検索する - 侍ズム


タグ :
このエントリーをはてなブックマークに追加