27.5. クエリ作成用の API

クエリを自動的にパースするだけではなく、クエリを API で作成することもできます。

ユーザクエリは、API で作成したクエリを組み合わせて作成することができます。 クエリパーサを使用して、文字列からクエリを作成します。

<?php
$query = Zend_Search_Lucene_Search_QueryParser::parse($queryString);

27.5.1. クエリパーサの例外

クエリパーサは、二種類の例外を発生させます。

  • Zend_Search_Lucene_Exception がスローされるのは、 クエリパーサ自体に何らかの問題が発生した場合です。

  • Zend_Search_Lucene_Search_QueryParserException がスローされるのは、 クエリの構文エラーが発生した場合です。

つまり、Zend_Search_Lucene_Search_QueryParserException を捕捉して適切なメッセージを表示させるようにしておくことが大切です。

<?php
try {
    $query = Zend_Search_Lucene_Search_QueryParser::parse($queryString);
} catch (Zend_Search_Lucene_Search_QueryParserException $e) {
    echo "クエリの構文エラー: " . $e->getMessage() . "\n";
}

Zend_Search_Lucene オブジェクトの find() メソッドでも同様のテクニックを使えます。

27.5.2. 単一の単語のクエリ

ひとつの単語を使用した検索を行うためのものです。

文字列によるクエリ

word1
        

あるいは

API で作成するクエリ

<?php
$term  = new Zend_Search_Lucene_Index_Term('word1', 'field1');
$query = new Zend_Search_Lucene_Search_Query_Term($term);
$hits  = $index->find($query);

単語のフィールドは任意で指定します。 指定しなかった場合は、Zend_Search_Lucene は全フィールドを対象に検索します。

<?php
$term  = new Zend_Search_Lucene_Index_Term('word1');  // インデックス化されている全フィールドから 'word1' を探します
$query = new Zend_Search_Lucene_Search_Query_Term($term);
$hits  = $index->find($query);

27.5.3. 複数の単語のクエリ

単語の組み合わせによる検索を行うためのものです。

各単語は、required (必須)prohibited (禁止)neither (どちらでもない) のいずれかを指定することができます。

  • required を指定した場合、 この単語を含まないドキュメントはクエリにマッチしません。

  • prohibited を指定した場合、 この単語を含むドキュメントはクエリにマッチしません。

  • neither を指定した場合、 この単語を含むドキュメントは除外されるわけでもなく、 この単語を含まなければマッチしないというわけでもありません。 ただし、クエリにマッチするためには、 この単語のうち最低ひとつを含まなければなりません。

つまり、必須単語のみのクエリに「どちらでもない (オプション)」 単語を追加しても、結果セットは変わりません。 ただ、オプションの単語にマッチした結果が結果セットの先頭に移動します。

以下の両方の方法が使用可能です。

文字列によるクエリ

+word1 author:word2 -word3
  • 必須の単語には '+' を使用します。

  • 禁止する単語には '-' を使用します。

  • 検索するドキュメントフィールドを指定するには 'field:' を先頭につけます。これが省略された場合は 'contents' が使用されます。

あるいは

API で作成するクエリ

<?php
$query = new Zend_Search_Lucene_Search_Query_MultiTerm();

$query->addTerm(new Zend_Search_Lucene_Index_Term('word1'), true);
$query->addTerm(new Zend_Search_Lucene_Index_Term('word2'), null);
$query->addTerm(new Zend_Search_Lucene_Index_Term('word3'), false);

$hits  = $index->find($query);

$signs 配列に、単語の種別についての情報を含めます。

  • 必須の単語には true を使用します。

  • 禁止する単語には false を使用します。

  • 必須・禁止のどちらでもない場合は null を使用します。

27.5.4. フレーズクエリ

熟語による検索を行うためのものです。

フレーズクエリはとても柔軟性の高いもので、 完全な熟語だけでなく曖昧な熟語の検索も可能になります。

熟語の途中で隙間をあけたり、複数の単語を同じ位置に指定したりもできます (これは、解析器によって別の目的で作成されます。 例えば、単語の重みを増すためにある単語を重複させたり、 類義語をひとつの位置にまとめたりします)。

<?php
$query1 = new Zend_Search_Lucene_Search_Query_Phrase();

// 'word1' を 0 番目の位置に追加します。
$query1->addTerm(new Zend_Search_Lucene_Index_Term('word1'));

// 'word2' を 1 番目の位置に追加します。
$query1->addTerm(new Zend_Search_Lucene_Index_Term('word2'));

// 'word3' を 3 番目の位置に追加します。
$query1->addTerm(new Zend_Search_Lucene_Index_Term('word3'), 3);

...

$query2 = new Zend_Search_Lucene_Search_Query_Phrase(
                array('word1', 'word2', 'word3'), array(0,1,3));

...

// 隙間をあけないクエリ
$query3 = new Zend_Search_Lucene_Search_Query_Phrase(
                array('word1', 'word2', 'word3'));

...

$query4 = new Zend_Search_Lucene_Search_Query_Phrase(
                array('word1', 'word2'), array(0,1), 'annotation');

フレーズクエリを作成するには、コンストラクタで一気に構築してしまう方法と Zend_Search_Lucene_Search_Query_Phrase::addTerm() メソッドでひとつひとつ作成する方法に 2 通りがあります。

Zend_Search_Lucene_Search_Query_Phrase クラスのコンストラクタで、 オプションの 3 つの引数を指定することができます。

<?php
Zend_Search_Lucene_Search_Query_Phrase([array $terms[, array $offsets[, string $field]]]);

$terms は文字列の配列で、 フレーズを構成する単語が含まれます。指定しなかったり null を渡したりした場合は、空のクエリが作成されます。

$offsets は整数の配列で、 フレーズ内の単語の位置を指定します。指定しなかったり null を渡したりした場合は、単語の位置は array(0, 1, 2, 3, ...) であると解釈されます。

$field は文字列で、検索対象となるドキュメントのフィールドを指定します。 指定しなかったり null を渡したりした場合は、デフォルトのフィールドが対象となります。 このバージョンの Zend_Search_Lucene では、デフォルトのフィールドは 'contents' となります。しかし、次のバージョンではこれを "any field" に変更する予定です。

したがって、

<?php
$query = new Zend_Search_Lucene_Search_Query_Phrase(array('zend', 'framework'));

は 'zend framework' を検索します。

<?php
$query = new Zend_Search_Lucene_Search_Query_Phrase(array('zend', 'download'), array(0, 2));

は 'zend ????? download' を検索し、'zend platform download' や 'zend studio download'、 'zend core download'、'zend framework download' などがマッチします

<?php
$query = new Zend_Search_Lucene_Search_Query_Phrase(array('zend', 'framework'), null, 'title');

は 'title' フィールドから 'zend framework' を検索します。

Zend_Search_Lucene_Search_Query_Phrase::addTerm() メソッドは 2 つの引数をとります。Zend_Search_Lucene_Index_Term オブジェクトが必須で、position はオプションです。

<?php
Zend_Search_Lucene_Search_Query_Phrase::addTerm(Zend_Search_Lucene_Index_Term $term[, integer $position]);

$term はフレーズ内の次の単語を指定します。 前の単語と同じフィールドを指していなければなりません。 そうでない場合は例外がスローされます。

$position は単語の位置を指定します。

したがって、

<?php
$query = new Zend_Search_Lucene_Search_Query_Phrase();
$query->addTerm(new Zend_Search_Lucene_Index_Term('zend'));
$query->addTerm(new Zend_Search_Lucene_Index_Term('framework'));

は 'zend framework' を検索します。

<?php
$query = new Zend_Search_Lucene_Search_Query_Phrase();
$query->addTerm(new Zend_Search_Lucene_Index_Term('zend'), 0);
$query->addTerm(new Zend_Search_Lucene_Index_Term('framework'), 2);

は 'zend ????? download' を検索し、'zend platform download' や 'zend studio download'、 'zend core download'、'zend framework download' などがマッチします

<?php
$query = new Zend_Search_Lucene_Search_Query_Phrase();
$query->addTerm(new Zend_Search_Lucene_Index_Term('zend', 'title'));
$query->addTerm(new Zend_Search_Lucene_Index_Term('framework', 'title'));

は 'title' フィールドから 'zend framework' を検索します。

曖昧度は、フレーズの間に別の単語が何個まで入ることを許すのかを設定します。 ゼロの場合は、完全な熟語検索となります。大きな値を指定すると、 WITHIN 演算子や NEAR 演算子と同様な動作となります。

曖昧度とは、クエリの中で各単語の位置を何段階移動させられるかを表します。 例えば、2 つの単語の順番を入れ替えるには 2 段階の移動が必要です (最初の単語を、次の単語のもうひとつ先まで移動させます)。 そのため、語順を入れ替えることを許可したいのなら、曖昧度は少なくとも 2 以上にしなければなりません。

正確にマッチしているほうが、曖昧に (sloppy) マッチしているものより高スコアとなります。そのため、 検索結果は正確度の順に並べ替えられます。曖昧度のデフォルトはゼロで、 これは完全に一致するもののみを対象とします。

曖昧度は、クエリを作成した後で設定することができます。

<?php
// 隙間をあけないクエリ
$query = new Zend_Search_Lucene_Search_Query_Phrase(array('word1', 'word2'));

// 'word1 word2'、'word1 ... word2' を検索します
$query->setSlop(1);
$hits1 = $index->find($query);

// 'word1 word2'、'word1 ... word2'、
// 'word1 ... ... word2'、'word2 word1' を検索します
$query->setSlop(2);
$hits2 = $index->find($query);