Azure Cognitive Search のフィルター

"フィルター" では、クエリの実行前にコンテンツを含めたり除外したりするための値ベースの条件を提供します。 たとえば、日付、場所、または言語に基づいてドキュメントを含めるか除外します。 フィルターは、個々のフィールドに対して指定されます。 フィルター式でフィールド定義を使用する場合は、その属性が "フィルター可能" に設定されている必要があります。

フィルターは、 OData フィルター式の構文を使用して指定します。 フルテキスト検索とは対照的に、フィルターは一致が正確な場合にのみ成功します。

フィルターを使用する場合

フィルターは、いくつかの検索エクスペリエンス ("近くを検索" の地理空間検索、ファセット ナビゲーション、ユーザーが閲覧を許可されているドキュメントのみを表示するセキュリティ フィルターなど) の基盤です。 これらいずれかのエクスペリエンスを実装する場合、フィルターは必須です。 これは、地理座標、ユーザーが選択したファセット カテゴリ、または要求側のセキュリティ ID を提供する検索クエリにアタッチされるフィルターです。

一般的なシナリオには次のようなものがあります。

  • インデックスの内容に基づいて検索結果をスライスする。 ホテルの場所、カテゴリ、アメニティを持つスキーマを指定すると、条件 (シアトル、水辺、眺望) を明示的に一致させるフィルターを作成することができます。

  • フィルター依存関係を含めて検索エクスペリエンスを実装する。

    • ファセット ナビゲーションでは、フィルターを使用して、ユーザーが選択したファセット カテゴリが渡されます。
    • 地理空間検索の場合、地域内または距離で一致する "近くを探す" アプリや関数で現在地の座標を渡すためにフィルターを使います。
    • セキュリティ フィルターではセキュリティ識別子がフィルター条件として渡されます。インデックスの一致は、ドキュメントに対するアクセス権のプロキシとして機能します。
  • "数値検索" を実行する。 数値フィールドは取得可能で、検索結果に表示できますが、個々に検索することはできません (フルテキスト検索に従うため)。 数値データに基づく選択条件が必要な場合は、フィルターを使用します。

フィルターの実行方法

クエリ時に、フィルター パーサーは入力として条件を受け取り、式をツリーとして表されるアトミックなブール式に変換し、フィルター ツリーをインデックスのフィルター可能なフィールドで評価します。

フィルターは検索と並行して実行され、ドキュメントの取得と関連性のスコア付けのためにダウンストリーム処理に含めるドキュメントを特定します。 フィルターを検索文字列と組み合わせて使用すると、以降の検索操作での再指定を効果的に減らすことができます。 フィルターを単独で使用すると (たとえば、search=* ではクエリ文字列が空です)、フィルター条件が唯一の入力になります。

フィルターを定義する

フィルターは OData 式であり、Cognitive Search によってサポートされるフィルター構文で表現されます。

検索操作に 1 つのフィルターを指定できますが、フィルター自体には複数のフィールド、複数の条件、および複数のフルテキスト検索式 (ismatch 関数を使用する場合) を含めることができます。 マルチパートのフィルター式では、任意の順序で述語を指定できます (演算子の優先順位の規則に従います)。 特定の順序で述語を並べ替えても、感知できるほどパフォーマンスが向上することはありません。

フィルター式に関する制限の 1 つとして、要求サイズの上限があります。 要求全体として (フィルターを含め)、POST の場合は最大 16 MB、GET の場合は最大 8 KB です。 また、フィルター式内の句の数にも制限があります。 目安として数百単位の句がある場合、上限に達する危険性があります。 サイズが無制限のフィルターを生成しない方法でアプリケーションを設計することをお勧めします。

次の例は、いくつかの API で典型的なフィルター定義を表しています。

POST https://[service name].search.windows.net/indexes/hotels/docs/search?api-version=2020-06-30
{
    "search": "*",
    "filter": "Rooms/any(room: room/BaseRate lt 150.0)",
    "select": "HotelId, HotelName, Rooms/Description, Rooms/BaseRate"
}
    parameters =
        new SearchParameters()
        {
            Filter = "Rooms/any(room: room/BaseRate lt 150.0)",
            Select = new[] { "HotelId", "HotelName", "Rooms/Description" ,"Rooms/BaseRate"}
        };

    var results = searchIndexClient.Documents.Search("*", parameters);

フィルター パターン

以下に、フィルター シナリオの使用パターン例をいくつか紹介します。 その他のアイデアについては、OData 式の構文 >「例」を参照してください。

  • クエリ文字列がないスタンドアロンの $filter。関係があるドキュメントをフィルター式で完全に修飾できる場合に役立ちます。 クエリ文字列がない場合、字句または言語の分析、スコア付け、優先度付けはありません。 検索文字列がアスタリスクのみであることに注意してください。これは、"すべてのドキュメントを照合する" ことを意味しています。

    {
      "search": "*",
      "filter": "Rooms/any(room: room/BaseRate ge 60 and room/BaseRate lt 300) and Address/City eq 'Honolulu"
    }
    
  • クエリ文字列と $filter の組み合わせ。フィルターによってサブセットが作成され、クエリ文字列は、フィルターされたサブセットに対するフルテキスト検索に用語入力を提供します。 用語 (walking distance theaters) を追加することにより、結果に検索スコアが導入され、用語に最も一致するドキュメントが上位にランク付けされます。 フィルターとクエリ文字列の併用は、最も一般的な使用パターンです。

    {
      "search": "walking distance theaters",
      "filter": "Rooms/any(room: room/BaseRate ge 60 and room/BaseRate lt 300) and Address/City eq 'Seattle'"
    }
    
    
  • 複合クエリ。"or" で区切られ、それぞれに独自のフィルター条件があります (たとえば、'dog' の 'beagles'、'cat' の 'siamese')。 or で結合された式は個別に評価され、各式に一致するドキュメントの和集合が応答で返されます。 この使用パターンは、search.ismatchscoring 関数を使用して実行されます。 また、スコア付けなしバージョンである search.ismatch を使用することもできます。

    # Match on hostels rated higher than 4 OR 5-star motels.
    $filter=search.ismatchscoring('hostel') and Rating ge 4 or search.ismatchscoring('motel') and Rating eq 5
    
    # Match on 'luxury' or 'high-end' in the description field OR on category exactly equal to 'Luxury'.
    $filter=search.ismatchscoring('luxury | high-end', 'Description') or Category eq 'Luxury'&$count=true
    

    or の代わりに and を指定して、search.ismatchscoring によるフルテキスト検索とフィルターを結合することもできますが、これは検索要求で search および $filter パラメーターを使用することと機能的に同じです。 たとえば、次の 2 つのクエリでは同じ結果が生成されます。

    $filter=search.ismatchscoring('pool') and Rating ge 4
    
    search=pool&$filter=Rating ge 4
    

フィルターのフィールド要件

REST API では、フィルター可能の設定は単純型フィールドの場合は既定で "オン" です。 フィルター可能なフィールドはインデックス サイズが大きくなります。実際にフィルターで使用する予定がないフィールドの場合は、"filterable": false を設定してください。 フィールド定義の設定の詳細については、「Create Index」(インデックスの作成) を参照してください。

.NET SDK では、フィルター可能の設定は既定でオフです。 対応する SearchField オブジェクトの IsFilterable プロパティtrue に設定することで、フィールドをフィルター可能にすることができます。 次の例では、属性は、インデックス定義にマップされるモデル クラスの BaseRate プロパティで設定されています。

[IsFilterable, IsSortable, IsFacetable]
public double? BaseRate { get; set; }

既存のフィールドをフィルター可能にする

既存のフィールドを変更してフィルター可能にすることはできません。 代わりに、新しいフィールドを追加するか、インデックスを再構築する必要があります。 インデックスの再構築またはフィールドへの再入力の詳細については、Azure Cognitive Search のインデックスを再構築する方法に関するページをご覧ください。

テキスト フィルターの基礎

テキスト フィルターでは、文字列フィールドと、フィルターに指定したリテラル文字列とを照合します: $filter=Category eq 'Resort and Spa'

フルテキスト検索とは異なり、テキスト フィルターには字句解析や単語区切り処理がないため、比較は完全一致のみです。 たとえば、フィールド f に "sunny day" が含まれる場合、$filter=f eq 'sunny' は一致しませんが、$filter=f eq 'sunny day' は一致します。

テキスト文字列では大文字と小文字が区別されます。つまり、テキスト フィルターでは既定で大文字と小文字が区別されます。 たとえば、$filter=f eq 'Sunny day' では "sunny day" は見つかりません。 ただし、ノーマライザーを使用することで、フィルター処理で大文字と小文字が区別されないようにできます。

テキストをフィルター処理するためのアプローチ

アプローチ 説明 使用する場合
search.in 区切られた文字列のリストに対してフィールドを照合する関数です。 セキュリティ フィルターや、多数の未加工テキスト値を文字列フィールドと照合する必要があるフィルターに推奨されます。 search.in 関数は、速度を重視して設計されているため、eqor を使用して各文字列とフィールドを明示的に比較するよりもはるかに高速です。
search.ismatch フルテキスト検索操作と、厳格なブール型フィルター操作を同じフィルター式に混在させることができる関数です。 1 つの要求で複数の検索フィルターを組み合わせる場合は、search.ismatch (または、このスコア付けバージョンである search.ismatchscoring) を使用します。 また、contains フィルターに使用して、大きな文字列内の一部の文字列をフィルターすることができます。
$filter=field operator string ユーザー定義の式は、フィールド、演算子、および値で構成されます。 文字列フィールドと文字列値の間の完全一致を検索する場合は、これを使用します。

数値フィルターの基礎

フルテキスト検索の文脈では、数値フィールドは searchable ではありません。 文字列のみがフルテキスト検索の対象になります。 たとえば、検索用語として 99.99 と入力しても、価格が 99.99 ドルの項目は取得されません。 代わりに、ドキュメントの文字列フィールドに 99 という数字が含まれる項目が表示されます。 そのため、数値データがある場合、範囲、ファセット、グループなどのフィルターに使用することが前提となります。

数値フィールド (価格、サイズ、SKU、ID) を含むドキュメントで、フィールドが retrievable とマークされている場合、検索結果にはそれらの値が表示されます。 ここで大事な点は、フルテキスト検索は数値フィールドの種類には適用できないということです。

次のステップ

まずポータルの Search エクスプローラーで、$filter パラメーターを使用したクエリを送信します。 real-estate-sample インデックスでは、検索バーに次のフィルターされたクエリを貼り付けると、興味深い結果になります。

# Geo-filter returning documents within 5 kilometers of Redmond, Washington state
# Use $count=true to get a number of hits returned by the query
# Use $select to trim results, showing values for named fields only
# Use search=* for an empty query string. The filter is the sole input

search=*&$count=true&$select=description,city,postCode&$filter=geo.distance(location,geography'POINT(-122.121513 47.673988)') le 5

# Numeric filters use comparison like greater than (gt), less than (lt), not equal (ne)
# Include "and" to filter on multiple fields (baths and bed)
# Full text search is on John Leclerc, matching on John or Leclerc

search=John Leclerc&$count=true&$select=source,city,postCode,baths,beds&$filter=baths gt 3 and beds gt 4

# Text filters can also use comparison operators
# Wrap text in single or double quotes and use the correct case
# Full text search is on John Leclerc, matching on John or Leclerc

search=John Leclerc&$count=true&$select=source,city,postCode,baths,beds&$filter=city gt 'Seattle'

その他の例を使用して作業する場合は、OData フィルター式の構文 >「例」を参照してください。

関連項目