索引の作成
Zend_Search_Luceneでは、検索を実行するために必要な情報をあらかじめ索引という形で作成しておきます。この索引はZend_Search_Luceneのインスタンスそのもので、そこに検索対象の文書を登録していくことで索引を作成します。
ここで登録する文書は、生のテキストデータそのものではなく、含まれている単語や構造などが解析してあるものを登録します。実はここがミソで、この「解析」の結果はユーザーが準備するため、どのような文書をどのように検索できるようにするかは完全にユーザーの側で決めることができます(決める必要がある、とも言えます)。
索引の構造は図1のようになっています。このように、索引には文書がいくつか登録されており、それぞれの文書の中にはその文書にどのような情報が含まれているかが、フィールドという単位で整理して記録されています。
それぞれのフィールドには、どのような検索に合致するかの情報や、解析前の生のデータが登録されています。
索引の操作
索引を作成・操作するにはZend_Search_Luceneのメソッドを利用します。一番最初に、まず索引を作成する際には静的メソッドのZend_Search_Lucene::create
を利用しZend_Search_Luceneのインスタンスを作ります。既に作成した索引を次回以降使うには、同じく静的メソッドのZend_Search_Lucene::open
を使用します。このZend_Search_Luceneのインスタンスに対してaddDocument
メソッドで文書を登録したり、find
メソッドで検索したりする、というのが基本的な使い方です。
(1)索引の作成 <?php $index = Zend_Search_Lucene::create('索引の名前'); //$doc1, $doc2... に文書を作成 $index->addDocument($doc1); $index->addDocument($doc2); ... (2)索引への文書の追加 <?php $index = Zend_Search_Lucene::open('索引の名前'); //$doc1, $doc2... に文書を作成 $index->addDocument($doc1); $index->addDocument($doc2); ... (3)検索の実行 <?php $index = Zend_Search_Lucene::open('索引の名前'); //$query にクエリを作成 $hits = $index->find($query); ...
ここで、Zend_Search_Luceneの主なメソッドの一覧を示しておきます。
分類 | メソッド | 引数 | 説明 |
静的 | create | $directory | $directoryという名前の索引を作成し、それを返す。 |
open | $directory | $directoryという名前の索引を開き、それを返す。 | |
setDefaultSearchField | $fieldName | 検索対象のフィールドを$fieldNameに指定する。$fieldNameは標準はnullで、その場合にはすべてのフィールドが検索対象となる。 | |
getDefaultSearchField | (なし) | 検索対象のフィールドを返す。 | |
インスタンス | getDirectory | (なし) | 索引の名前を返す。 |
numDocs | (なし) | この索引に実際に登録されている文書の数を返す。 | |
count | (なし) | この索引に登録されている文書の数を、既に削除したものも含めて返す。 | |
maxDoc | (なし) | この索引に登録されている文書のIDの最大値より、一つ大きい値を返す。 | |
isDeleted | $id | IDが$idである文書が削除されているかを調べる。 | |
find | $query | 検索を実行する | |
getFieldNames | $indexed | 登録されているフィールドの名前を、配列として返す。 | |
addDocument | $document | 文書$documentを登録する。 | |
getDocument | $id | IDが$idである文書を返す。 | |
delete | $id | IDが$idである文書を削除する。 |
主なメソッドだけでも結構ありますが、基本的な使い方をする分には静的メソッドのcreate
とopen
、インスタンスメソッドのaddDocument
だけで、一通りのことはできます。
文書の操作
次に、索引に登録する文書について見ていきます。先程も述べたとおり、ここで言う文章は生のデータそのものではなく、データを検索に便利なように加工したものをフィールドという単位で整理したものになっています。
例えば写真を整理するための索引を作ろうとしているとしましょう。写真のデータ自体は別のウェブサーバに置きますが、写真に関するメモや写真のサムネイルは索引に登録するとして、必要そうな情報を表にしてみました。
項目 | 説明 | 検索対象 | データを格納 | 文として解析 |
location | 撮影した場所 | ○ | ○ | × |
date | 撮影した日付 | ○ | ○ | × |
url | 写真のURL | × | ○ | × |
thumbnail | サムネイル | × | ○ | × |
note | メモ | ○ | ○ | ○ |
ここで、必要な情報の項目一つが文書のフィールドに対応します。Zend_Search_Luceneでは、サムネイルのようにバイナリデータを格納するフィールドも作成することもできれば、URLのように検索の対象としない情報を格納するためのフィールドを準備することもできます。
また、メモは文章になっているので検索する場合には単語に分ける必要がありますが、そのような処理を行うかも指定することもできます。なお、ここでは登場しませんが、「データを格納しない」フィールドも作成することができます。これは、例えば巨大なHTMLファイルに対応する文書を作成する場合、そのHTMLファイルを索引に登録してしまうと索引のファイルサイズが大きくなり過ぎてしまうため、検索用のデータのみを登録して生データを索引に登録しないということも可能になっているのです。
このような文書を作成するサンプルコードをリスト4に示します。
<?php require_once 'Zend/Search/Lucene.php'; //文字コードに関するおまじない(次回説明) Zend_Search_Lucene_Analysis_Analyzer::setDefault( new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8()); // (1) - 索引インスタンスの作成 $index = Zend_Search_Lucene::create('codezine-index'); // (2) - 文書の作成 // インスタンスの作成 $doc = new Zend_Search_Lucene_Document(); // フィールドの登録 $doc->addField(Zend_Search_Lucene_Field::keyword("location", "Here")); $doc->addField(Zend_Search_Lucene_Field::keyword("date", "2009-01-01")); $doc->addField(Zend_Search_Lucene_Field::unIndexed("url", "http://localhost/pics/01.jpg")); //サムネイルを登録する場合には下のようにします //(今回は画像ファイルを準備していないのでコメントアウトしています) //$doc->addField(Zend_Search_Lucene_Field::binary("thumbnail", $thumbnail); $doc->addField(Zend_Search_Lucene_Field::text("note", "Took for CodeZine article."); // (3) - 索引へ文書の登録 $index->addDocument($doc); ...
文書の作成はリスト4の(2)で行っており、Zend_Search_Lucene_Documentのインスタンスを作成した後、addField
メソッドで順番にフィールドを登録しています。各フィールドはZend_Search_Lucene_Fieldの静的メソッドを利用して作成しています。
メソッド | 引数 | 説明 |
__get | $offset | (文書変数)->(フィールド名)という形式でフィールドにアクセスできる。 |
addField | $field | フィールド$fieldを追加する。 |
getFieldNames | (なし) | 登録されているフィールドの名前の配列を返す。 |
getField | $fieldName | 名前が$fieldNameであるフィールドを返す。 |
getFieldValue | $fieldName | 名前が$fieldNameであるフィールドの中身のテキストを返す。 |
getFieldUtf8Value | $fieldName | 名前が$fieldNameであるフィールドの中身のテキストをUTF-8で返す。 |
またZend_Search_Lucene_Fieldには次のようなメソッドがあります。
分類 | メンバ | 引数 | 説明 |
静的メソッド | keyword | $name, $value, $encoding | 名前$nameで値が$valueのフィールドを作成する。このフィールドは検索対象で、値も記録され、値は単語として処理される。 |
unIndexed | $name, $value, $encoding | 名前$nameで値が$valueのフィールドを作成する。このフィールドは検索対象ではないが、値は記録される。また、値は文章として処理される。 | |
binary | $name, $value, $encoding | 名前$nameで値が$valueのフィールドを作成する。このフィールドは検索対象ではないが、値は記録される。値はバイナリデータとして処理される。 | |
text | $name, $value, $encoding | 名前$nameで値が$valueのフィールドを作成する。このフィールドは検索対象で、値も記録され、値は文章として処理される。 | |
unStored | $name, $value, $encoding | 名前$nameで値が$valueのフィールドを作成する。このフィールドは検索対象だが、値も記録されない。値は文章として処理される。 | |
プロパティ | name | (なし) | このフィールドの名前。 |
value | (なし) | このフィールドの値。 | |
isStored | (なし) | 値が記録されているか。標準ではfalse。 | |
isIndexed | (なし) | 検索対象か。標準ではtrue。 | |
isTokenized | (なし) | 文章として処理されるか。標準ではtrue。 | |
インスタンスメソッド | getUtf8Value | (なし) | 値をUTF-8に変換して返す。 |
上の例では使用しませんでしたが、unStored静的メソッドが「値は記録されないが検索対象となるフィールド」を作成するための静的メソッドになっています。