# クエリ言語

Java Lucene および `Zend_Search_Lucene` では、非常に強力なクエリ言語を使用できます。

これらの言語はほぼ同じものですが、微妙に異なる点もあります。 異なる点については以下で説明します。

Java Lucene のクエリ言語の文法についての完全な文書は ここ にあります。

## 用語

クエリは、単語と演算子から成り立ちます。単語には三種類の形式があります。 単一の単語、フレーズ、そしてサブクエリです。

単一の単語とは、"test" や "hello" のようなひとつの単語です。

フレーズとは、ダブルクォートで囲まれた複数の単語のグループ、たとえば "hello dolly" です。

サブクエリとは、括弧で囲まれたクエリ、たとえば "(hello dolly)" です。

複数の単語を論理演算子で組み合わせることで、より複雑なクエリを作成できます (以下を参照ください)。

## フィールド

Lucene は、フィールド指定したデータをサポートしています。 検索を行う際には、クエリを指定することもできますし、 デフォルトのフィールドを使用することもできます。 フィールド名はインデックス化されたデータに依存します。また、 デフォルトのフィールドは現在の設定によって決まります。

Java Lucene との最初の (そしてもっとも大きな) 違いは、デフォルトでは すべてのフィールド が検索の対象になるということです。

`Zend_Search_Lucene` クラスにはふたつの静的メソッドがあり、 この設定を操作できます。

    $defaultSearchField = Zend_Search_Lucene::getDefaultSearchField();
    ...
    Zend_Search_Lucene::setDefaultSearchField('contents');

`NULL` 値は、すべてのフィールドを検索の対象とすることを意味します。 これがデフォルトの設定です。

特定のフィールドを検索するには、まずフィールド名をタイプし、その後にコロン ":" を続け、探したい単語を指定します。

例を見てみましょう。Lucene インデックスにはふたつのフィールド title および text があり、text がデフォルトのフィールドであるとします。 タイトルが "The Right Way" で本文に "don't go this way" が含まれるドキュメントを探したいなら、

    title:"The Right Way" AND text:go

あるいは下記にします。 "text" はデフォルトのフィールドなので、フィールドの指定は必須ではなくなります。

    title:"Do it right" AND go

注意: フィールドが有効なのは、その直後にある単語、 フレーズあるいはサブクエリだけであることに注意しましょう。つまり、下記のクエリ は "Do" だけを title フィールドから探し、"it" や "right" はデフォルトのフィールドから探します。デフォルトのフィールドが `NULL` に設定されている場合は、"it" や "right" はすべてのフィールドから探します。

    title:Do it right

## ワイルドカード

Lucene は、単一の文字あるいは複数の文字を表すワイルドカードをサポートしています これは、単語検索でのみ使用可能です (フレーズクエリでは使用できません)。

単一の文字を表すワイルドカードは "?" です。

複数の文字を表すワイルドカードは "*" です。

単一文字のワイルドカードは、 単語の中の "?" を別の一文字に置き換えたものにマッチする単語を探します。 たとえば、"text" あるいは "test" を探したい場合はこうします。

    te?t

複数文字のワイルドカードは、0 個以上の任意の数の文字に対応します。 たとえば test、tests あるいは tester を探したい場合はこうします。

    test*

"?" や "*" は単語のどの部分でも使え、 また両方を同時に使うこともできます。たとえば 下記は、"write" や "wrote"、"written"、"rewrite"、"rewrote" などに対応します。

    *wr?t*

ZF 1.7.7 以降、ワイルドカードパターンにはワイルドカード以外のプレフィックスが必要となりました。 デフォルトのプレフィックスの長さは 3 (Java Lucene と同じ) です。 つまり "*", "te?t", "*wr?t*" といった単語は例外を引き起こします この例外は `Zend_Search_Lucene_Search_QueryParserException` ではなく `Zend_Search_Lucene_Exception` となることに注意しましょう。 この例外がスローされるのは、クエリの書き換え (実行) 操作のときです。。

これは、`Zend_Search_Lucene_Search_Query_Wildcard::getMinPrefixLength()` および `Zend_Search_Lucene_Search_Query_Wildcard::setMinPrefixLength()` メソッドで変更できます。

## 単語の修正子

Lucene は、クエリの単語を修飾して幅広い検索オプションを指定することをサポートしています。

"~" 修正子を使用すると、 フレーズに対する近接検索や個別の単語に対するあいまい検索が可能となります。

## 範囲検索

範囲検索は、フィールドの値の下限と上限を指定して その範囲に含まれるドキュメントを探すものです。 最大値と最小値そのものを含めることも含めないこともできます。 並べ替えは、辞書順で行われます。

    mod_date:[20020101 TO 20030101]

これは、mod_date フィールドの値が 20020101 から 20030101 (両端を含む) であるドキュメントを探します。 範囲検索は、日付フィールド以外でも使えることに注意しましょう。

    title:{Aida TO Carmen}

これは、タイトルが Aida から Carmen までの間にあるドキュメントを探します。 ただし、Aida および Carmen は含めません。

両端の値を含めるには角括弧 []、含めない場合は波括弧 {} でクエリを指定します。

フィールドを指定しなかった場合は、`Zend_Search_Lucene` はすべてのフィールドに対して範囲検索を行います。

    {Aida TO Carmen}

## あいまい検索

`Zend_Search_Lucene` は、Java Lucene と同様にあいまい検索をサポートします。 これは、レーベンシュタイン距離のアルゴリズムにもとづくものです。 あいまい検索を行うには、チルダ記号 "~" を単語の最後に指定します。 たとえば、"roam" と似たスペルの単語を探すには、次のようなあいまい検索を使用します。

    roam~

この検索は、foam あるいは roams といった単語にマッチします。 (オプションの) 追加のパラメータによって、 あいまい検索の程度を指定できます。 このパラメータの値は 0 から 1 までの間となり、 1 に近づくほど、類似点が多い単語にのみマッチするようになります。 たとえば次のように使用します。

    roam~0.8

このパラメータを省略した場合のデフォルトは 0.5 です。

## マッチする単語の制限

ワイルドカード検索や範囲検索、あいまい検索は、マッチする単語が多くなりすぎる可能性があります。 そんな場合は検索のパフォーマンスが大幅に低下してしまいます。

そこで、`Zend_Search_Lucene` はマッチする単語数の制限をクエリ (サブクエリ) 単位で設定します。 この制限を取得したり設定したりするには `Zend_Search_Lucene::getTermsPerQueryLimit()` および `Zend_Search_Lucene::setTermsPerQueryLimit($limit)` メソッドを使用します。

デフォルトのマッチ数の制限は、クエリ単位で 1024 です。

## 近接検索

Lucene は、複数の単語が指定した範囲内にあらわれる状態の検索をサポートしています。 近接検索を行うには、チルダ記号 "~" をフレーズの最後に指定します。 たとえば、"Zend" と "Framework" がお互い 10 ワードの範囲内にあらわれるドキュメントを検索するにはこうします。

    "Zend Framework"~10

## 単語の強調

Java Lucene および `Zend_Search_Lucene` は、 見つかった単語にもとづいてドキュメントの関連度を提供します。 ある単語の関連性を高くするには、キャレット記号 "^" に強調度 (数値) をあわせたものを、検索する単語の最後につなげます。 強調度を高くするほど、その単語の関連性が高くなります。

この機能を使用すると、単語の強調度によってドキュメントの関連性を制御できるようになります。 たとえば

    PHP framework

を検索しようとしており、単語 "PHP" をより重視したいとしましょう。 そんな場合は ^ 記号と強調度を単語の後に続けます。つまり

    PHP^4 framework

のようにします。これにより、 PHP という単語を含むドキュメントがより重視されるようになります。 フレーズやサブクエリを強調することも可能です。たとえば

    "PHP framework"^4 "Zend Framework"

のようになります。デフォルトの強調度は 1 です。強調度には正の数値を指定しますが、 1 より小さくする (たとえば 0.2 など) ことも可能です。

## 論理演算子

論理演算子によって、複数の単語を組み合わせることができます。 Lucene では、論理演算子として AND、"+"、OR、NOT および "-" をサポートしています。Java Lucene では論理演算子をすべて大文字にする必要がありますが、 `Zend_Search_Lucene` ではその必要はありません。

論理クエリを作成するための方式は、大きく AND、OR および NOT の組と "+"、"-" の組に分けられます。Java Lucene とは異なり、`Zend_Search_Lucene` ではこれらの二つの組を混ぜて使うことはできません。

AND/OR/NOT 形式を使用する場合は、AND/OR 演算子がすべてのクエリ単語の間に存在する必要があります。 各単語の前には NOT 演算子をつけることができます。AND 演算子の優先順位は OR より高くなります。これは Java Lucene の挙動とは異なります。

### AND

AND 演算子の意味は、"AND グループ" のすべての単語がドキュメントにマッチしなければならないということです。

"PHP framework" および "Zend Framework" を含むドキュメントを検索するには 下記を使用します。

    "PHP framework" AND "Zend Framework"

### OR

OR 演算子は、クエリをいくつかのオプションに分割します。

"PHP framework" あるいは "Zend Framework" を含むドキュメントを検索するには 下記を使用します。

    "PHP framework" OR "Zend Framework"

### NOT

NOT 演算子は、NOT の後に続く単語を含むドキュメントを除外します。 しかし "AND グループ" が NOT 演算子つきの単語しか含まない場合は、 インデックス化されたドキュメント全体ではなく空の結果を返します。

"PHP framework" を含むけれども "Zend Framework" を含まないドキュメントを検索するには 下記を使用します。

    "PHP framework" AND NOT "Zend Framework"

### &&、|| および ! 演算子

&&、|| および ! は、それぞれ AND、OR および NOT 演算子の代わりに使用します。

### +

"+" 演算子 (必須演算子) は、 "+" 記号の後の単語が必ずドキュメントにマッチしなければならないことを意味します。

"Zend" を必ず含み、"Framework" を含んでも含まなくてもかまわないドキュメントを検索するには 下記を使用します。

    +Zend Framework

### -

"-" 演算子 (禁止演算子) は、 "-" 記号の後の単語を含むドキュメントを検索結果から除外します。

"PHP framework" を含むけれども "Zend Framework" を含まないドキュメントを検索するには 下記を使用します。

    "PHP framework" -"Zend Framework"

### 演算子なし

演算子を使用しなかった場合は、 その挙動は "デフォルトの boolean 演算子" として定義されます。

これは、デフォルトでは 'OR' となります。

つまり、その単語は任意となるということです。 その単語はドキュメント中に存在するかもしれないし、しないかもしれません。 ただ、その単語を含むドキュメントのほうが高いスコアとなります。

"PHP framework" は必須で "Zend Framework" は含んでも含まなくてもかまわないドキュメントを検索するには 下記を使用します。

    +"PHP framework" "Zend Framework"

デフォルトの boolean 演算子を設定したり取得したりするには、それぞれ `Zend_Search_Lucene_Search_QueryParser::setDefaultOperator($operator)` および `Zend_Search_Lucene_Search_QueryParser::getDefaultOperator()` を使用します。

これらのメソッドで使用する定数は、 `Zend_Search_Lucene_Search_QueryParser::B_AND` および `Zend_Search_Lucene_Search_QueryParser::B_OR` です。

## グループ化

Java Lucene および `Zend_Search_Lucene` では、 括弧を使用して条件をグループ化することによるサブクエリの作成をサポートしています。 これは、クエリのロジックを制御したい場合や異なるスタイルの論理クエリを共用したい場合などに便利です。

    +(framework OR library) +php

`Zend_Search_Lucene` は、あらゆるレベルのサブクエリをサポートしています。

## フィールドのグループ化

Lucene では、括弧を使用して複数の条件をひとつのフィールドに適用できます。

タイトルに単語 "return" とフレーズ "pink panther" の両方を含むドキュメントを検索するには 下記を使用します。Zend_Search_Lucene は、あらゆるレベルのサブクエリをサポートしています。

    title:(+return +"pink panther")

## 特殊文字のエスケープ

Lucene は、クエリの文法に含まれる特殊文字のエスケープをサポートしています。 特殊文字に含まれるの文字は次のとおりです。

+ - && || ! ( ) { } [ ] ^ " ~ * ? : \

+ および - が単一の単語の中に含まれる場合は、通常の文字として扱われます。

これらの文字をエスケープするには、その文字の前に \ をつけます。 たとえば、(1+1):2 を検索するには下記を使用します。

    \(1\+1\)\:2