<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 15341 -->
<sect1 id="zend.search.lucene.query-api">
    <title>クエリ作成用の API</title>

    <para>
        文字列のクエリを自動的にパースするだけではなく、クエリを API で作成することもできます。
    </para>

    <para>
        ユーザクエリは、API で作成したクエリを組み合わせて作成することができます。
        クエリパーサを使用して、文字列からクエリを作成します。
        <programlisting role="php"><![CDATA[
$query = Zend_Search_Lucene_Search_QueryParser::parse($queryString);
]]></programlisting>
    </para>

    <sect2 id="zend.search.lucene.queries.exceptions">
        <title>クエリパーサの例外</title>

        <para>
        クエリパーサは、二種類の例外を発生させます。
        <itemizedlist>
            <listitem>
                <para>
                    <classname>Zend_Search_Lucene_Exception</classname> がスローされるのは、
                    クエリパーサ自体に何らかの問題が発生した場合です。
                </para>
            </listitem>
            <listitem>
                <para>
                    <classname>Zend_Search_Lucene_Search_QueryParserException</classname>
                    がスローされるのは、クエリの構文エラーが発生した場合です。
                </para>
            </listitem>
        </itemizedlist>
        つまり、<classname>Zend_Search_Lucene_Search_QueryParserException</classname>
        を捕捉して適切なメッセージを表示させるようにしておくことが大切です。
        <programlisting role="php"><![CDATA[
try {
    $query = Zend_Search_Lucene_Search_QueryParser::parse($queryString);
} catch (Zend_Search_Lucene_Search_QueryParserException $e) {
    echo "クエリの構文エラー: " . $e->getMessage() . "\n";
}
]]></programlisting>
        </para>

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

        <para>
            バージョン 1.5 以降では、クエリのパース時の例外はデフォルトで抑制されるようになります。
            クエリ言語に反するクエリが渡された場合は、現在のデフォルトの解析器を用いてそれをトークン化し、
            トークン化された単語で検索します。

            例外を有効にするには
            <classname>Zend_Search_Lucene_Search_QueryParser::dontSuppressQueryParsingExceptions()</classname>
            メソッドを使用します。
            <classname>Zend_Search_Lucene_Search_QueryParser::suppressQueryParsingExceptions()</classname> メソッドおよび
            <classname>Zend_Search_Lucene_Search_QueryParser::queryParsingExceptionsSuppressed()</classname>
            メソッドも、例外処理の振る舞いを変更するためのものです。

        </para>

    </sect2>

    <sect2 id="zend.search.lucene.queries.term-query">
        <title>単一の単語のクエリ</title>
        <para>
            ひとつの単語を使用した検索を行うためのものです。
        </para>

        <para>
        文字列によるクエリ
        </para>
        <programlisting role="querystring"><![CDATA[
word1
]]></programlisting>

        <para>あるいは</para>

        <para>
        API で作成するクエリ
        </para>
        <programlisting role="php"><![CDATA[
$term  = new Zend_Search_Lucene_Index_Term('word1', 'field1');
$query = new Zend_Search_Lucene_Search_Query_Term($term);
$hits  = $index->find($query);
]]></programlisting>

        <para>
            単語のフィールドは任意で指定します。
            指定しなかった場合は、<classname>Zend_Search_Lucene</classname>
            は全フィールドを対象に検索します。
            <programlisting role="php"><![CDATA[
// インデックス化されている全フィールドから 'word1' を探します
$term  = new Zend_Search_Lucene_Index_Term('word1');
$query = new Zend_Search_Lucene_Search_Query_Term($term);
$hits  = $index->find($query);
]]></programlisting>
        </para>
    </sect2>

    <sect2 id="zend.search.lucene.queries.multiterm-query">
        <title>複数の単語のクエリ</title>
        <para>
            複数の単語の組み合わせによる検索を行うためのものです。
        </para>

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

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

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

        <para>
            以下の両方の方法が使用可能です。
        </para>

        <para>
            文字列によるクエリ
        </para>
        <programlisting role="querystring"><![CDATA[
+word1 author:word2 -word3
]]></programlisting>

        <itemizedlist>
            <listitem>
                <para>
                    必須の単語には '+' を使用します。
                </para>
            </listitem>
            <listitem>
                <para>
                    禁止する単語には '-' を使用します。
                </para>
            </listitem>
            <listitem>
                <para>
                    検索するドキュメントフィールドを指定するには 'field:'
                    を先頭につけます。これが省略された場合は 'contents' が使用されます。
                </para>
            </listitem>
        </itemizedlist>

        <para>あるいは</para>

        <para>
        API で作成するクエリ
        </para>
        <programlisting role="php"><![CDATA[
$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', 'author'),
                null);
$query->addTerm(new Zend_Search_Lucene_Index_Term('word3'), false);

$hits  = $index->find($query);
]]></programlisting>

        <para>
            MultiTerm クエリのコンストラクタで、単語のリストを指定することもできます。
            <programlisting role="php"><![CDATA[

$terms = array(new Zend_Search_Lucene_Index_Term('word1'),
               new Zend_Search_Lucene_Index_Term('word2', 'author'),
               new Zend_Search_Lucene_Index_Term('word3'));
$signs = array(true, null, false);

$query = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $signs);

$hits  = $index->find($query);
]]></programlisting>
        </para>

        <para>
            <code>$signs</code> 配列に、単語の種別についての情報を含めます。
            <itemizedlist>
                <listitem>
                    <para>
                        必須の単語には <code>true</code> を使用します。
                    </para>
                </listitem>
                <listitem>
                    <para>
                        禁止する単語には <code>false</code> を使用します。
                    </para>
                </listitem>
                <listitem>
                    <para>
                        必須・禁止のどちらでもない場合は <code>null</code> を使用します。
                    </para>
                </listitem>
            </itemizedlist>
        </para>
    </sect2>

    <sect2 id="zend.search.lucene.queries.boolean-query">
        <title>Boolean クエリ</title>
        <para>
            Boolean クエリを使用すると、他のクエリや boolean 演算子を用いたクエリを作成できます。
        </para>

        <para>
            セット内の各サブクエリは、<emphasis>required (必須)</emphasis> か
            <emphasis>prohibited (禁止)</emphasis>、あるいは <emphasis>optional (オプション)</emphasis> として定義します。

            <itemizedlist>
                <listitem>
                    <para>
                        <emphasis>required</emphasis> は、このサブクエリにマッチしないドキュメントはクエリにマッチしません。
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <emphasis>prohibited</emphasis> は、このサブクエリにマッチするドキュメントはクエリにマッチしません。
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <emphasis>optional</emphasis> の場合、このサブクエリにマッチしなければマッチしないというわけではなく、このサブクエリにマッチしたものをを除外するというわけでもありません。
                        しかし、クエリにマッチするには少なくともひとつのサブクエリにマッチする必要があります。
                    </para>
                </listitem>
            </itemizedlist>
        </para>

        <para>
            必須サブクエリを含むクエリにオプションのサブクエリを追加しても結果は変わりません。
            ただ、オプションのサブクエリを使用することで、マッチしたドキュメントのスコアが変わります。
        </para>

        <para>
            boolean クエリには、両方の方式の検索メソッドが使用可能です。
        </para>

        <para>
            文字列によるクエリ
        </para>
        <programlisting role="querystring"><![CDATA[
+(word1 word2 word3) author:(word4 word5) -word6
]]></programlisting>

        <itemizedlist>
            <listitem>
                <para>
                    必須サブクエリには '+' を使用します。
                </para>
            </listitem>
            <listitem>
                <para>
                    禁止サブクエリには '-' を使用します。
                </para>
            </listitem>
            <listitem>
                <para>
                    検索するドキュメントフィールドを指定するには 'field:'
                    省略した場合はすべてのフィールドを検索します。
                </para>
            </listitem>
        </itemizedlist>

        <para>あるいは</para>

        <para>
        API で作成するクエリ
        </para>
        <programlisting role="php"><![CDATA[

$query = new Zend_Search_Lucene_Search_Query_Boolean();

$subquery1 = new Zend_Search_Lucene_Search_Query_MultiTerm();
$subquery1->addTerm(new Zend_Search_Lucene_Index_Term('word1'));
$subquery1->addTerm(new Zend_Search_Lucene_Index_Term('word2'));
$subquery1->addTerm(new Zend_Search_Lucene_Index_Term('word3'));

$subquery2 = new Zend_Search_Lucene_Search_Query_MultiTerm();
$subquery2->addTerm(new Zend_Search_Lucene_Index_Term('word4', 'author'));
$subquery2->addTerm(new Zend_Search_Lucene_Index_Term('word5', 'author'));

$term6 = new Zend_Search_Lucene_Index_Term('word6');
$subquery3 = new Zend_Search_Lucene_Search_Query_Term($term6);

$query->addSubquery($subquery1, true  /* required */);
$query->addSubquery($subquery2, null  /* optional */);
$query->addSubquery($subquery3, false /* prohibited */);

$hits  = $index->find($query);
]]></programlisting>

        <para>
            Boolean クエリのコンストラクタで、単語のリストを指定することもできます。
            <programlisting role="php"><![CDATA[

...
$subqueries = array($subquery1, $subquery2, $subquery3);
$signs = array(true, null, false);

$query = new Zend_Search_Lucene_Search_Query_Boolean($subqueries, $signs);

$hits  = $index->find($query);
]]></programlisting>
        </para>

        <para>
            <code>$signs</code> 配列に、サブクエリの種別についての情報を含めます。
            <itemizedlist>
                <listitem>
                    <para>
                        必須のサブクエリには <code>true</code> を使用します。
                    </para>
                </listitem>
                <listitem>
                    <para>
                        禁止するサブクエリには <code>false</code> を使用します。
                    </para>
                </listitem>
                <listitem>
                    <para>
                        必須・禁止のどちらでもないサブクエリには <code>null</code> を使用します。
                    </para>
                </listitem>
            </itemizedlist>
        </para>

        <para>
            boolean 演算子を使用する各クエリは、符号記法や API を用いて書き換えることができます。たとえば
            <programlisting role="querystring"><![CDATA[
word1 AND (word2 AND word3 AND NOT word4) OR word5
]]></programlisting>
            は次のクエリと同等です。
            <programlisting role="querystring"><![CDATA[
(+(word1) +(+word2 +word3 -word4)) (word5)
]]></programlisting>
        </para>
    </sect2>

    <sect2 id="zend.search.lucene.queries.wildcard">
        <title>ワイルドカードクエリ</title>
        <para>
            ワイルドカードクエリは、指定したパターンに一致する複数の単語を探すためのものです。
        </para>

        <para>
            '?' は、ひとつの文字を表すワイルドカードです。
        </para>

        <para>
            '*' は、複数の文字を表すワイルドカードです。
        </para>

        <para>
            文字列によるクエリ
            <programlisting role="querystring"><![CDATA[
field1:test*
]]></programlisting>
        </para>

        <para>あるいは</para>

        <para>
            API で作成するクエリ
            <programlisting role="php"><![CDATA[
$pattern = new Zend_Search_Lucene_Index_Term('test*', 'field1');
$query = new Zend_Search_Lucene_Search_Query_Wildcard($pattern);
$hits  = $index->find($query);
]]></programlisting>
        </para>

        <para>
            フィールドの指定はオプションです。省略した場合は、
            <classname>Zend_Search_Lucene</classname> は全フィールドを対象に検索を行います。
            <programlisting role="php"><![CDATA[
$pattern = new Zend_Search_Lucene_Index_Term('test*');
$query = new Zend_Search_Lucene_Search_Query_Wildcard($pattern);
$hits  = $index->find($query);
]]></programlisting>
        </para>
    </sect2>

    <sect2 id="zend.search.lucene.queries.fuzzy">
        <title>あいまいクエリ</title>
        <para>
            あいまいクエリは、指定した単語に似た単語を含むドキュメントを探すためのものです。
        </para>

        <para>
            文字列によるクエリ
            <programlisting role="querystring"><![CDATA[
field1:test~
]]></programlisting>
            このクエリは、'test' 'text' 'best' といった単語を含むドキュメントにマッチします。
        </para>

        <para>or</para>

        <para>
            API で作成するクエリ
            <programlisting role="php"><![CDATA[

$term = new Zend_Search_Lucene_Index_Term('test', 'field1');
$query = new Zend_Search_Lucene_Search_Query_Fuzzy($term);
$hits  = $index->find($query);
]]></programlisting>
        </para>

        <para>
            オプションの類似度は、"~" 記号の後に指定します。
        </para>

        <para>
            文字列によるクエリ
            <programlisting role="querystring"><![CDATA[
field1:test~0.4
]]></programlisting>
        </para>

        <para>or</para>

        <para>
            API で作成するクエリ
            <programlisting role="php"><![CDATA[

$term = new Zend_Search_Lucene_Index_Term('test', 'field1');
$query = new Zend_Search_Lucene_Search_Query_Fuzzy($term, 0.4);
$hits  = $index->find($query);
]]></programlisting>
        </para>

        <para>
            単語のフィールドはオプションです。
            このフィールドを省略した場合、<classname>Zend_Search_Lucene</classname>
            は各ドキュメントのすべてのフィールドを検索します。
            <programlisting role="php"><![CDATA[

$term = new Zend_Search_Lucene_Index_Term('test');
$query = new Zend_Search_Lucene_Search_Query_Fuzzy($term);
$hits  = $index->find($query);
]]></programlisting>
        </para>
    </sect2>

    <sect2 id="zend.search.lucene.queries.phrase-query">
        <title>フレーズクエリ</title>
        <para>
            熟語による検索を行うためのものです。
        </para>

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

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

        <programlisting role="php"><![CDATA[
$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');
]]></programlisting>

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

        <para>
            <classname>Zend_Search_Lucene_Search_Query_Phrase</classname> クラスのコンストラクタで、
            オプションの 3 つの引数を指定することができます。
        </para>
        <programlisting role="php"><![CDATA[
Zend_Search_Lucene_Search_Query_Phrase(
    [array $terms[, array $offsets[, string $field]]]
);
]]></programlisting>

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

        <para>
            <code>$offsets</code> は整数の配列で、
            フレーズ内の単語の位置を指定します。指定しなかったり
            null を渡したりした場合は、単語の位置はシーケンシャルであり、
            すきまはないと解釈されます。
        </para>

        <para>
            <code>$field</code> は文字列で、検索対象となるドキュメントのフィールドを指定します。
            指定しなかったり null を渡したりした場合は、デフォルトのフィールドが対象となります。
        </para>

        <para>
            したがって、
        </para>
        <programlisting role="php"><![CDATA[
$query =
    new Zend_Search_Lucene_Search_Query_Phrase(array('zend', 'framework'));
]]></programlisting>
        <para>
            は 'zend framework' を検索します。
        </para>

        <programlisting role="php"><![CDATA[
$query = new Zend_Search_Lucene_Search_Query_Phrase(
                 array('zend', 'download'), array(0, 2)
             );
]]></programlisting>
        <para>
            は 'zend ????? download' を検索し、'zend platform download' や 'zend studio download'、
            'zend core download'、'zend framework download' などがマッチします
        </para>

        <programlisting role="php"><![CDATA[
$query = new Zend_Search_Lucene_Search_Query_Phrase(
                 array('zend', 'framework'), null, 'title'
             );
]]></programlisting>

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

        <para>
            <classname>Zend_Search_Lucene_Search_Query_Phrase::addTerm()</classname> メソッドは
            2 つの引数をとります。<classname>Zend_Search_Lucene_Index_Term</classname>
            オブジェクトが必須で、position はオプションです。
        </para>
        <programlisting role="php"><![CDATA[
Zend_Search_Lucene_Search_Query_Phrase::addTerm(
    Zend_Search_Lucene_Index_Term $term[, integer $position]
);
]]></programlisting>

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

        <para>
            <code>$position</code> は単語の位置を指定します。
        </para>

        <para>
            したがって、
        </para>
        <programlisting role="php"><![CDATA[
$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'));
]]></programlisting>
        <para>
            は 'zend framework' を検索します。
         </para>

        <programlisting role="php"><![CDATA[
$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);
]]></programlisting>
        <para>
            は 'zend ????? download' を検索し、'zend platform download' や 'zend studio download'、
            'zend core download'、'zend framework download' などがマッチします
        </para>
        <programlisting role="php"><![CDATA[
$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'));
]]></programlisting>
        <para>
            は 'title' フィールドから 'zend framework' を検索します。
        </para>

        <para>
            曖昧度は、フレーズの間に別の単語が何個まで入ることを許すのかを設定します。
            ゼロの場合は、完全な熟語検索となります。大きな値を指定すると、
            WITHIN 演算子や NEAR 演算子と同様な動作となります。
        </para>
        <para>
            曖昧度とは、クエリの中で各単語の位置を何段階移動させられるかを表します。
            例えば、2 つの単語の順番を入れ替えるには 2 段階の移動が必要です
            (最初の単語を、次の単語のもうひとつ先まで移動させます)。
            そのため、語順を入れ替えることを許可したいのなら、曖昧度は少なくとも
            2 以上にしなければなりません。
        </para>
        <para>
            正確にマッチしているほうが、曖昧に (sloppy)
            マッチしているものより高スコアとなります。そのため、
            検索結果は正確度の順に並べ替えられます。曖昧度のデフォルトはゼロで、
            これは完全に一致するもののみを対象とします。
        </para>
        <para>
            曖昧度は、クエリを作成した後で設定することができます。
        </para>
        <programlisting role="php"><![CDATA[
// 隙間をあけないクエリ
$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);
]]></programlisting>
    </sect2>

    <sect2 id="zend.search.lucene.queries.range">
        <title>範囲クエリ</title>
        <para>
            <link linkend="zend.search.lucene.query-language.range">範囲クエリ</link>
            は、指定した範囲にある単語を探すためのものです。
        </para>

        <para>
            文字列によるクエリ
            <programlisting role="querystring"><![CDATA[
mod_date:[20020101 TO 20030101]
title:{Aida TO Carmen}
]]></programlisting>
        </para>

        <para>あるいは</para>

        <para>
            API で作成するクエリ
            <programlisting role="php"><![CDATA[
$from = new Zend_Search_Lucene_Index_Term('20020101', 'mod_date');
$to   = new Zend_Search_Lucene_Index_Term('20030101', 'mod_date');
$query = new Zend_Search_Lucene_Search_Query_Range(
                 $from, $to, true // inclusive
             );
$hits  = $index->find($query);
]]></programlisting>
        </para>

        <para>
            フィールドの指定はオプションです。省略した場合は、
            <classname>Zend_Search_Lucene</classname> は全フィールドを対象に検索を行います。
            <programlisting role="php"><![CDATA[
$from = new Zend_Search_Lucene_Index_Term('Aida');
$to   = new Zend_Search_Lucene_Index_Term('Carmen');
$query = new Zend_Search_Lucene_Search_Query_Range(
                 $from, $to, false // non-inclusive
             );
$hits  = $index->find($query);
]]></programlisting>
        </para>

        <para>
            上限あるいは下限のどちらか一方を null にすることができます
            (両方を null にすることはできません)。この場合、Zend_Search_Lucene
            は「先頭から指定した値まで」あるいは「指定した値から最後まで」
            という条件で検索します。
            <programlisting role="php"><![CDATA[
// searches for ['20020101' TO ...]
$from = new Zend_Search_Lucene_Index_Term('20020101', 'mod_date');
$query = new Zend_Search_Lucene_Search_Query_Range(
                 $from, null, true // inclusive
             );
$hits  = $index->find($query);
]]></programlisting>
        </para>
    </sect2>

</sect1>

<!--
vim:se ts=4 sw=4 et:
-->
