Azure Search での OData コレクション フィルターの概要Understanding OData collection filters in Azure Search

Azure Search でコレクションのフィールドのフィルター処理を行うには、any および all 演算子ラムダ式と共に使用できます。To filter on collection fields in Azure Search, you can use the any and all operators together with lambda expressions. ラムダ式は範囲変数を参照するブール式です。Lambda expressions are Boolean expressions that refer to a range variable. any および all 演算子はほとんどのプログラミング言語の for ループに似ており、範囲変数がループ変数、ラムダ式がループ本体の役割を果たします。The any and all operators are analogous to a for loop in most programming languages, with the range variable taking the role of loop variable, and the lambda expression as the body of the loop. 範囲変数は、ループの反復処理の間、コレクションの "現在" の値になります。The range variable takes on the "current" value of the collection during iteration of the loop.

少なくとも、概念的にはそのように動作します。At least that's how it works conceptually. 実際には、Azure Search でのフィルターの実装は、for ループの動作方法とまったく異なります。In reality, Azure Search implements filters in a very different way to how for loops work. この違いがユーザーには認識されないのが理想ですが、特定の状況ではそうなりません。Ideally, this difference would be invisible to you, but in certain situations it isn't. 最終的な結果として、ラムダ式を作成するときに従う必要がある規則があります。The end result is that there are rules you have to follow when writing lambda expressions.

この記事では、Azure Search でのこれらのフィルターの実行方法を調べることにより、コレクション フィルターの規則が存在する理由について説明します。This article explains why the rules for collection filters exist by exploring how Azure Search executes these filters. 複雑なラムダ式で高度なフィルターを作成する場合、この記事はフィルターで可能性のあることとその理由を理解するのに役立ちます。If you're writing advanced filters with complex lambda expressions, you may find this article helpful in building your understanding of what's possible in filters and why.

コレクション フィルターの規則と例については、「Azure Search での OData コレクション フィルターのトラブルシューティング」をご覧ください。For information on what the rules for collection filters are, including examples, see Troubleshooting OData collection filters in Azure Search.

コレクション フィルターに制限がある理由Why collection filters are limited

コレクションのすべての種類に対してフィルターのすべての機能がサポートされていないことについては、3 つの基になる理由があります。There are three underlying reasons why not all filter features are supported for all types of collections:

  1. 特定のデータ型では、特定の演算子のみがサポートされています。Only certain operators are supported for certain data types. たとえば、ltgt などを使ってブール値 truefalse を比較しても意味がありません。For example, it doesn't make sense to compare the Boolean values true and false using lt, gt, and so on.
  2. Azure Search では、Collection(Edm.ComplexType) 型のフィールドに対する相関検索はサポートされていません。Azure Search doesn't support correlated search on fields of type Collection(Edm.ComplexType).
  3. Azure Search では、逆インデックスを使って、コレクションを含むすべてのデータ型に対するフィルター処理が実行されます。Azure Search uses inverted indexes to execute filters over all types of data, including collections.

最初の理由は、単に、OData 言語と EDM 型システムの定義方法の結果によるものです。The first reason is just a consequence of how the OData language and EDM type system are defined. 後の 2 つについては、この記事の残りの部分で詳しく説明します。The last two are explained in more detail in the rest of this article.

複合オブジェクトのコレクションに対して複数のフィルター条件を適用するとき、条件は " 、コレクション内の各オブジェクト" に適用されるため、条件は相関されます。When applying multiple filter criteria over a collection of complex objects, the criteria are correlated since they apply to each object in the collection. たとえば、次のフィルターでは、料金が 100 未満のデラックス ルームが 1 室以上あるホテルが返されます。For example, the following filter will return hotels that have at least one deluxe room with a rate less than 100:

Rooms/any(room: room/Type eq 'Deluxe Room' and room/BaseRate lt 100)

フィルター処理が "相関されない" 場合、上記のフィルターでは、1 つの部屋がデラックスで、別の部屋が基本料金 100 未満であるホテルが返される可能性があります。If filtering was uncorrelated, the above filter might return hotels where one room is deluxe and a different room has a base rate less than 100. ラムダ式の両方の句が同じ範囲変数 room に適用されるので、それでは意味がありません。That wouldn't make sense, since both clauses of the lambda expression apply to the same range variable, namely room. これが、そのようなフィルターが相関される理由です。This is why such filters are correlated.

ただし、フルテキスト検索では、特定の範囲変数を参照する方法はありません。However, for full-text search, there's no way to refer to a specific range variable. フィールド検索を使って、次のような完全な Lucene クエリを発行するものとします。If you use fielded search to issue a full Lucene query like this one:

Rooms/Type:deluxe AND Rooms/Description:"city view"

この場合、1 つの部屋がデラックスで、別の部屋の説明に "city view" という語句が含まれるホテルが返される可能性があります。you may get hotels back where one room is deluxe, and a different room mentions "city view" in the description. たとえば、Id1 である以下のドキュメントは、クエリに一致します。For example, the document below with Id of 1 would match the query:

{
  "value": [
    {
      "Id": "1",
      "Rooms": [
        { "Type": "deluxe", "Description": "Large garden view suite" },
        { "Type": "standard", "Description": "Standard city view room" }
      ]
    },
    {
      "Id": "2",
      "Rooms": [
        { "Type": "deluxe", "Description": "Courtyard motel room" }
      ]
    }
  ]
}

その理由は、次の表に示すように、Rooms/Type ではドキュメント全体の Rooms/Type フィールドの分析されたすべての語句が参照され、Rooms/Description フィールドについても同様であるためです。The reason is that Rooms/Type refers to all the analyzed terms of the Rooms/Type field in the entire document, and similarly for Rooms/Description, as shown in the tables below.

フルテキスト検索に対して Rooms/Type が格納される方法:How Rooms/Type is stored for full-text search:

Rooms/Type での語句Term in Rooms/Type ドキュメント IDDocument IDs
deluxedeluxe 1、21, 2
standardstandard 11

フルテキスト検索に対して Rooms/Description が格納される方法:How Rooms/Description is stored for full-text search:

Rooms/Description での語句Term in Rooms/Description ドキュメント IDDocument IDs
courtyardcourtyard 22
citycity 11
gardengarden 11
largelarge 11
motelmotel 22
roomroom 1、21, 2
standardstandard 11
suitesuite 11
viewview 11

したがって、基本的に "部屋の Type が 'Deluxe Room' と等しく、その同じ部屋BaseRate が 100 未満であるドキュメントと一致する" ことを示す上記のフィルターとは異なり、検索クエリでは "Rooms/Type に語句 'deluxe' が含まれ、Rooms/Description に語句 'city view' が含まれるドキュメントと一致する" ことが示されます。So unlike the filter above, which basically says "match documents where a room has Type equal to 'Deluxe Room' and that same room has BaseRate less than 100", the search query says "match documents where Rooms/Type has the term "deluxe" and Rooms/Description has the phrase "city view". 後者の場合、フィールドを相関できる個別の部屋の概念はありません。There's no concept of individual rooms whose fields can be correlated in the latter case.

注意

Azure Search への相関検索の追加のサポートを希望する場合は、こちらの User Voice 項目に投票してください。If you would like to see support for correlated search added to Azure Search, please vote for this User Voice item.

逆インデックスとコレクションInverted indexes and collections

複雑なコレクションに対するラムダ式での制限は、Collection(Edm.Int32)Collection(Edm.GeographyPoint) などの単純なコレクションに対する制限よりはるかに少ないことにお気付きかもしれません。You may have noticed that there are far fewer restrictions on lambda expressions over complex collections than there are for simple collections like Collection(Edm.Int32), Collection(Edm.GeographyPoint), and so on. これは、Azure Search では、複雑なコレクションはサブドキュメントの実際のコレクションとしてを格納されるのに対し、単純なコレクションはコレクションとして格納されないためです。This is because Azure Search stores complex collections as actual collections of sub-documents, while simple collections aren't stored as collections at all.

たとえば、オンライン小売店用のインデックスでの seasons のようなフィルター可能な文字列コレクション フィールドについて考えます。For example, consider a filterable string collection field like seasons in an index for an online retailer. このインデックスには、次のようなドキュメントがアップロードされる可能性があります。Some documents uploaded to this index might look like this:

{
  "value": [
    {
      "id": "1",
      "name": "Hiking boots",
      "seasons": ["spring", "summer", "fall"]
    },
    {
      "id": "2",
      "name": "Rain jacket",
      "seasons": ["spring", "fall", "winter"]
    },
    {
      "id": "3",
      "name": "Parka",
      "seasons": ["winter"]
    }
  ]
}

seasons フィールドの値は逆インデックスと呼ばれる構造に格納され、次のようになります。The values of the seasons field are stored in a structure called an inverted index, which looks something like this:

期間Term ドキュメント IDDocument IDs
springspring 1、21, 2
summersummer 11
fallfall 1、21, 2
winterwinter 2、32, 3

このデータ構造は、次のような 1 つの質問に対して非常に高速に回答するように設計されています: 特定の語句はどのドキュメントに含まれているか。This data structure is designed to answer one question with great speed: In which documents does a given term appear? この質問に答える処理は、コレクションのループというより、単純な等値チェックに近いものです。Answering this question works more like a plain equality check than a loop over a collection. 実際、文字列コレクションの場合、ラムダ式内の any に対する比較演算子として Azure Search では eq しか許可されないのはこのためです。In fact, this is why for string collections, Azure Search only allows eq as a comparison operator inside a lambda expression for any.

このような等価性を踏まえて、次に、or を使用して同じ範囲変数でどのように複数の等価性チェックを組み合わせることができるかを見てみましょう。Building up from equality, next we'll look at how it's possible to combine multiple equality checks on the same range variable with or. それは、代数と量指定子の分配則に従って動作します。It works thanks to algebra and the distributive property of quantifiers. 次の式This expression:

seasons/any(s: s eq 'winter' or s eq 'fall')

は以下に匹敵します。is equivalent to:

seasons/any(s: s eq 'winter') or seasons/any(s: s eq 'fall')

そして、2 つの各 any サブ式を、逆インデックスを使って効率的に実行できます。and each of the two any sub-expressions can be efficiently executed using the inverted index. また、量指定子の否定法則により、次の式Also, thanks to the negation law of quantifiers, this expression:

seasons/all(s: s ne 'winter' and s ne 'fall')

は以下に匹敵します。is equivalent to:

not seasons/any(s: s eq 'winter' or s eq 'fall')

これが、ne および andall を使用できる理由です。which is why it's possible to use all with ne and and.

注意

詳細はこのドキュメントの範囲を超えますが、これらの同じ原則が、地理空間ポイントのコレクションに対する距離と交差のテストに拡張されます。Although the details are beyond the scope of this document, these same principles extend to distance and intersection tests for collections of geo-spatial points as well. これが、any で次のようになる理由です。This is why, in any:

  • geo.intersects を否定することはできませんgeo.intersects cannot be negated
  • geo.distance は、lt または le を使って比較する必要がありますgeo.distance must be compared using lt or le
  • 式を結合するには、and ではなく or を使う必要がありますexpressions must be combined with or, not and

all には逆の規則が適用されます。The converse rules apply for all.

ltgtlege の各演算子がサポートされるデータ型のコレクションをフィルター処理するときは、さまざまな式が許可されます (Collection(Edm.Int32) など)。A wider variety of expressions are allowed when filtering on collections of data types that support the lt, gt, le, and ge operators, such as Collection(Edm.Int32) for example. 具体的には、基になる比較式が and を使って範囲比較に結合されている限り、any においてand だけでなく or を使うことができ、それがさらに or を使って結合されます。Specifically, you can use and as well as or in any, as long as the underlying comparison expressions are combined into range comparisons using and, which are then further combined using or. ブール式のこの構造は選言標準形 (DNF) と呼ばれ、"ORs of ANDs" としても知られています。This structure of Boolean expressions is called Disjunctive Normal Form (DNF), otherwise known as "ORs of ANDs". 逆に、これらのデータ型に対する all のラムダ式は、連言標準形 (CNF) ("ANDs of ORs" としても知られます) になっている必要があります。Conversely, lambda expressions for all for these data types must be in Conjunctive Normal Form (CNF), otherwise known as "ANDs of ORs". Azure Search では、文字列の高速語句検索と同様に逆インデックスを使って効率的に実行できるため、そのような範囲比較が許可されます。Azure Search allows such range comparisons because it can execute them using inverted indexes efficiently, just like it can do fast term lookup for strings.

まとめると、ラムダ式で許可されることの経験則は次のようになります。In summary, here are the rules of thumb for what's allowed in a lambda expression:

  • any の内部では、等値、範囲比較、geo.intersectslt または le での geo.distance の比較など、"ポジティブ チェック" が常に許可されます (距離のチェックでは "近さ" は等価性と同じように考えます)。Inside any, positive checks are always allowed, like equality, range comparisons, geo.intersects, or geo.distance compared with lt or le (think of "closeness" as being like equality when it comes to checking distance).
  • any の内部では、or が常に許可されます。Inside any, or is always allowed. and は、範囲チェックを表現できるデータ型に対してだけ、ORs of ANDs (DNF) を使用する場合にのみ使用できます。You can use and only for data types that can express range checks, and only if you use ORs of ANDs (DNF).
  • all の内部では、規則は逆になります。"ネガティブ チェック" のみが許可され、and を常に使用でき、or は ANDs of ORs (CNF) として表される範囲チェックに対してだけ使用できます。Inside all, the rules are reversed -- only negative checks are allowed, you can use and always, and you can use or only for range checks expressed as ANDs of ORs (CNF).

実際には、これらはいずれにしても使用する可能性が最も高いフィルターの種類です。In practice, these are the types of filters you're most likely to use anyway. それでも、可能なことの境界を理解しておくと役に立ちます。It's still helpful to understand the boundaries of what's possible though.

許可されるフィルターと許可されないフィルターの種類の具体的な例については、「有効なコレクション フィルターを記述する方法」をご覧ください。For specific examples of which kinds of filters are allowed and which aren't, see How to write valid collection filters.

次の手順Next steps