Azure Search で複合データ型をモデル化する方法How to model complex data types in Azure Search

Azure Search インデックスの作成に使われる外部データセットは、さまざまな形状をしている可能性があります。External datasets used to populate an Azure Search index can come in many shapes. 場合によっては、階層や入れ子の下部構造が含まれます。Sometimes they include hierarchical or nested substructures. たとえば、単一の顧客に複数の住所が含まれるケース、単一の SKU に複数の色とサイズが含まれるケース、1 冊の書籍に複数の著者が存在するケースなどが挙げられます。Examples might include multiple addresses for a single customer, multiple colors and sizes for a single SKU, multiple authors of a single book, and so on. モデリングの用語では、このような構造は complex (複合)、compound (複合)、composite (複合)、または aggregate (集約) データ型と呼ばれることがあります。In modeling terms, you might see these structures referred to as complex, compound, composite, or aggregate data types. Azure Search でこの概念に対して使われる用語は 複合型 (complex type) です。The term Azure Search uses for this concept is complex type. Azure Search では、複合型は複合フィールドを使ってモデル化されます。In Azure Search, complex types are modeled using complex fields. 複合フィールドは、他の複合型も含めて任意のデータ型を使用できる子 (サブフィールド) が含まれるフィールドです。A complex field is a field that contains children (sub-fields) which can be of any data type, including other complex types. これは、プログラミング言語の構造化されたデータ型と同様の方法で機能します。This works in a similar way as structured data types in a programming language.

複合フィールドでは、データ型に応じて、ドキュメント内の 1 つのオブジェクトまたはオブジェクトの配列が表されます。Complex fields represent either a single object in the document, or an array of objects, depending on the data type. Edm.ComplexType 型のフィールドでは単一のオブジェクトが表され、Collection(Edm.ComplexType) 型のフィールドではオブジェクトの配列が表されます。Fields of type Edm.ComplexType represent single objects, while fields of type Collection(Edm.ComplexType) represent arrays of objects.

Azure Search は、複合型とコレクションをネイティブでサポートしています。Azure Search natively supports complex types and collections. これらの型を使うと、Azure Search インデックス内のほとんどすべての JSON 構造をモデル化できます。These types allow you to model almost any JSON structure in an Azure Search index. Azure Search API の以前のバージョンでは、フラット化された行セットのみをインポートできました。In previous versions of Azure Search APIs, only flattened row sets could be imported. 最新のバージョンでは、インデックスはソース データにより密接に調和できるようになりました。In the newest version, your index can now more closely correspond to source data. つまり、ソース データに複合型がある場合、インデックスも複合型を持つことができます。In other words, if your source data has complex types, your index can have complex types also.

Azure portal のデータのインポート ウィザードで読み込むことができる Hotels データ セットから始めることをお勧めします。To get started, we recommend the Hotels data set, which you can load in the Import data wizard in the Azure portal. ウィザードでは、ソース内の複合型が検出され、検出された構造に基づいてインデックス スキーマが提案されます。The wizard detects complex types in the source and suggests an index schema based on the detected structures.

注意

複合型のサポートは、api-version=2019-05-06 で一般提供されています。Support for complex types is generally available in api-version=2019-05-06.

検索ソリューションがコレクション内でフラット化されたデータセットの以前の回避策に基づいている場合は、インデックスを変更して、最新の API バージョンでサポートされている複合型を含めることをお勧めします。If your search solution is built on earlier workarounds of flattened datasets in a collection, you should change your index to include complex types as supported in the newest API version. API バージョンのアップグレードの詳細については、最新の REST API バージョンへのアップグレードまたは最新の .NET SDK バージョンへのアップグレードに関する記事を参照してください。For more information about upgrading API versions, see Upgrade to the newest REST API version or Upgrade to the newest .NET SDK version.

複合構造の例Example of a complex structure

次の JSON ドキュメントは、単純フィールドと複合フィールドで構成されています。The following JSON document is composed of simple fields and complex fields. AddressRooms などの複合フィールドには、サブフィールドがあります。Complex fields, such as Address and Rooms, have sub-fields. Address はドキュメント内の単一オブジェクトなので、サブフィールドには単一の値のセットがあります。Address has a single set of values for those sub-fields, since it's a single object in the document. 対照的に、Rooms のサブフィールドには、コレクション内の各オブジェクトに 1 つずつ、複数の値のセットがあります。In contrast, Rooms has multiple sets of values for its sub-fields, one for each object in the collection.

{
  "HotelId": "1",
  "HotelName": "Secret Point Motel",
  "Description": "Ideally located on the main commercial artery of the city in the heart of New York.",
  "Address": {
    "StreetAddress": "677 5th Ave",
    "City": "New York",
    "StateProvince": "NY"
  },
  "Rooms": [
    {
      "Description": "Budget Room, 1 Queen Bed (Cityside)",
      "Type": "Budget Room",
      "BaseRate": 96.99
    },
    {
      "Description": "Deluxe Room, 2 Double Beds (City View)",
      "Type": "Deluxe Room",
      "BaseRate": 150.99
    },
  ]
}

複合フィールドの作成Creating complex fields

他のインデックス定義と同様に、ポータル、REST API、または .NET SDK を使用して、複合型を含むスキーマを作成できます。As with any index definition, you can use the portal, REST API, or .NET SDK to create a schema that includes complex types.

次の例は、単純フィールド、コレクション、および複合型を含む JSON インデックス スキーマを示しています。The following example shows a JSON index schema with simple fields, collections, and complex types. 最上位レベルのフィールドと同様に、複合型内の各サブフィールドには型があり、場合によっては属性がある点に注意してください。Notice that within a complex type, each sub-field has a type and may have attributes, just as top-level fields do. スキーマは、上記のデータ例に対応しています。The schema corresponds to the example data above. Address はコレクションではない複合フィールドです (1 つのホテルには 1 つの住所があります)。Address is a complex field that isn't a collection (a hotel has one address). Rooms は複合コレクション フィールドです (1 つのホテルには多くの部屋があります)。Rooms is a complex collection field (a hotel has many rooms).

{
  "name": "hotels",
  "fields": [
    { "name": "HotelId", "type": "Edm.String", "key": true, "filterable": true },
    { "name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false },
    { "name": "Description", "type": "Edm.String", "searchable": true, "analyzer": "en.lucene" },
    { "name": "Address", "type": "Edm.ComplexType",
      "fields": [
        { "name": "StreetAddress", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false, "searchable": true },
        { "name": "City", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true },
        { "name": "StateProvince", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true }
      ]
    },
    { "name": "Rooms", "type": "Collection(Edm.ComplexType)",
      "fields": [
        { "name": "Description", "type": "Edm.String", "searchable": true, "analyzer": "en.lucene" },
        { "name": "Type", "type": "Edm.String", "searchable": true },
        { "name": "BaseRate", "type": "Edm.Double", "filterable": true, "facetable": true }
      ]
    }
  ]
}

複合フィールドの更新Updating complex fields

一般にフィールドに適用されるすべての再インデックス作成規則は、複合フィールドにも適用されます。All of the reindexing rules that apply to fields in general still apply to complex fields. ここでいくつかの主な規則を言い換えると、フィールドの追加にはインデックスの再構築が必要ありませんが、ほとんどの修正には必要です。Restating a few of the main rules here, adding a field doesn't require an index rebuild, but most modifications do.

定義に対する構造的な更新Structural updates to the definition

新しいサブフィールドは、インデックスを再構築することなく、いつでも複合フィールドに追加できます。You can add new sub-fields to a complex field at any time without the need for an index rebuild. たとえば、インデックスに最上位レベルのフィールドを追加する場合と同様に、"ZipCode" を Address に、"Amenities" を Rooms に追加することができます。For example, adding "ZipCode" to Address or "Amenities" to Rooms is allowed, just like adding a top-level field to an index. 既存のドキュメントでは、データを更新してそれらのフィールドに明示的にデータを入力するまで、新しいフィールドの値は null です。Existing documents have a null value for new fields until you explicitly populate those fields by updating your data.

最上位レベルのフィールドと同様に、複合型内の各サブフィールドには型があり、場合によっては属性がある点に注意してくださいNotice that within a complex type, each sub-field has a type and may have attributes, just as top-level fields do

データの更新Data updates

upload アクションを使用してインデックス内の既存のドキュメントを更新する処理は、複合フィールドと単純フィールドで同じように機能し、すべてのフィールドが置き換えられます。Updating existing documents in an index with the upload action works the same way for complex and simple fields -- all fields are replaced. ただし、merge (または既存のドキュメントに適用された場合は mergeOrUpload) は、すべてのフィールドで同じようには機能しません。However, merge (or mergeOrUpload when applied to an existing document) doesn't work the same across all fields. 具体的には、merge ではコレクション内の要素のマージがサポートされていません。Specifically, merge doesn't support merging elements within a collection. この制限は、プリミティブ型のコレクションと複合コレクションに対して存在します。This limitation exists for collections of primitive types and complex collections. コレクションを更新するには、完全なコレクション値を取得し、変更して、新しいコレクションを Index API 要求に含める必要があります。To update a collection, you'll need to retrieve the full collection value, make changes, and then include the new collection in the Index API request.

複合フィールドの検索Searching complex fields

自由形式の検索式は、複合型では期待どおりに機能します。Free-form search expressions work as expected with complex types. ドキュメント内の任意の場所にある検索可能なフィールドまたはサブフィールドが一致すると、そのドキュメント自体が一致します。If any searchable field or sub-field anywhere in a document matches, then the document itself is a match.

複数の用語と演算子があり、Lucene 構文で可能なように、一部の用語にフィールド名を指定すると、より細かい表現のクエリにすることができます。Queries get more nuanced when you have multiple terms and operators, and some terms have field names specified, as is possible with the Lucene syntax. たとえば、このクエリは、"Portland" と "OR" という 2 つの用語を Address フィールドの 2 つのサブフィールドに対して照合を試みます。For example, this query attempts to match two terms, "Portland" and "OR", against two sub-fields of the Address field:

search=Address/City:Portland AND Address/State:OR

このようなクエリは、フィルターとは異なり、フルテキスト検索では "非相関" です。Queries like this are uncorrelated for full-text search, unlike filters. フィルターでは、複合コレクションのサブフィールドに対するクエリを、any または all の範囲変数を使って相関させることができます。In filters, queries over sub-fields of a complex collection are correlated using range variables in any or all. 上の Lucene クエリでは、"Portland, Maine" および "Portland, Oregon" の両方と共に Oregon の他の都市を含むドキュメントが返されます。The Lucene query above returns documents containing both "Portland, Maine" and "Portland, Oregon", along with other cities in Oregon. このようになるのは、各句がドキュメント全体のそのフィールドのすべての値に適用され、"現在のサブ ドキュメント" という概念がないためです。This happens because each clause applies to all values of its field in the entire document, so there's no concept of a "current sub-document". これについて詳しくは、「Understanding OData collection filters in Azure Search」(Azure Search での OData コレクション フィルターについて) をご覧ください。For more information on this, see Understanding OData collection filters in Azure Search.

複合フィールドの選択Selecting complex fields

$select パラメーターは、検索結果に返すフィールドを選択するために使用されます。The $select parameter is used to choose which fields are returned in search results. このパラメーターを使用して複合フィールドの特定のサブフィールドを選択するには、スラッシュ (/) で区切った親フィールドとサブフィールドを含めます。To use this parameter to select specific sub-fields of a complex field, include the parent field and sub-field separated by a slash (/).

$select=HotelName, Address/City, Rooms/BaseRate

検索結果に必要な場合は、インデックス内のフィールドを Retrievable とマークする必要があります。Fields must be marked as Retrievable in the index if you want them in search results. $select ステートメントでは Retrievable とマークされたフィールドのみを使用できます。Only fields marked as Retrievable can be used in a $select statement.

複合フィールドのフィルター処理、ファセット、並べ替えFilter, facet, and sort complex fields

検索のフィルター処理とフィールド検索に使用されるものと同じ OData パス構文を、検索要求内のフィールドのファセット、並べ替え、および選択にも使用できます。The same OData path syntax used for filtering and fielded searches can also be used for faceting, sorting, and selecting fields in a search request. 複合型の場合、sortable または facetable とマークできるサブフィールド管理する規則が適用されます。For complex types, rules apply that govern which sub-fields can be marked as sortable or facetable. これらの規則について詳しくは、Create Index API reference (Create Index API リファレンス) に関する記事をご覧ください。For more information on these rules, see the Create Index API reference.

サブフィールドのファセットFaceting sub-fields

型が Edm.GeographyPoint または Collection(Edm.GeographyPoint) でない限り、すべてのサブフィールドは facetable とマークすることができます。Any sub-field can be marked as facetable unless it is of type Edm.GeographyPoint or Collection(Edm.GeographyPoint).

ファセットの結果で返されるドキュメント数は、複合コレクション (部屋) 内のサブドキュメントではなく、親ドキュメント (ホテル) に対して計算されます。The document counts returned in the facet results are calculated for the parent document (a hotel), not the sub-documents in a complex collection (rooms). たとえば、ホテルに 20 室の型 "suite" があるとします。For example, suppose a hotel has 20 rooms of type "suite". facet パラメーターを facet=Rooms/Type とすると、ファセット数は、部屋に対する 20 ではなく、ホテルに対する 1 になります。Given this facet parameter facet=Rooms/Type, the facet count will be one for the hotel, not 20 for the rooms.

複合フィールドの並べ替えSorting complex fields

並べ替え操作は、サブドキュメント (Rooms) ではなく、ドキュメント (Hotels) に適用されます。Sort operations apply to documents (Hotels) and not sub-documents (Rooms). Rooms のような複合型のコレクションがある場合は、Rooms では並べ替えることがまったくできないことを認識することが重要です。When you have a complex type collection, such as Rooms, it's important to realize that you can't sort on Rooms at all. 実際のところ、どのコレクションでも並べ替えることはできません。In fact, you can't sort on any collection.

並べ替え操作は、フィールドが単純フィールドでも、または複合型のサブフィールドでも、フィールドがドキュメントごとに単一値の場合に機能します。Sort operations work when fields have a single value per document, whether the field is a simple field, or a sub-field in a complex type. たとえば、ホテルごとに住所は 1 つだけなので Address/City は並べ替え可能であり、$orderby=Address/City では都市別にホテルが並べ替えられます。For example, Address/City is allowed to be sortable because there's only one address per hotel, so $orderby=Address/City will sort hotels by city.

複合フィールドでのフィルター処理Filtering on complex fields

フィルター式で複合フィールドのサブフィールドを参照することができます。You can refer to sub-fields of a complex field in a filter expression. フィールドのファセット、並べ替え、選択に使われるのと同じ OData パス構文を使うだけです。Just use the same OData path syntax that's used for faceting, sorting, and selecting fields. たとえば、次のフィルターではカナダのすべてのホテルが返されます。For example, the following filter will return all hotels in Canada:

$filter=Address/Country eq 'Canada'

複合コレクションのフィールドでフィルター処理するには、ラムダ式any および all 演算子を使うことができます。To filter on a complex collection field, you can use a lambda expression with the any and all operators. その場合、ラムダ式の範囲変数はサブフィールドを持つオブジェクトです。In that case, the range variable of the lambda expression is an object with sub-fields. それらのサブフィールドを標準の OData パス構文で参照することができます。You can refer to those sub-fields with the standard OData path syntax. たとえば、次のフィルターでは、デラックス ルームが少なくとも 1 つはあり、すべてが禁煙室であるすべてのホテルが返されます。For example, the following filter will return all hotels with at least one deluxe room and all non-smoking rooms:

$filter=Rooms/any(room: room/Type eq 'Deluxe Room') and Rooms/all(room: not room/SmokingAllowed)

最上位レベルの単純フィールドと同様に、複合フィールド内の単純サブフィールドは、インデックス定義で filterable 属性が true に設定されている場合にのみ、フィルターに含めることができます。As with top-level simple fields, simple sub-fields of complex fields can only be included in filters if they have the filterable attribute set to true in the index definition. 詳しくは、Create Index API リファレンス に関する記事をご覧ください。For more information, see the Create Index API reference.

次の手順Next steps

データのインポート ウィザードで Hotels データ セットを試してください。Try the Hotels data set in the Import data wizard. データにアクセスするには、readme に記載されている Cosmos DB 接続情報が必要です。You'll need the Cosmos DB connection information provided in the readme to access the data.

その情報を入手したら、ウィザードの最初の手順は新しい Azure Cosmos DB データ ソースを作成することです。With that information in hand, your first step in the wizard is to create a new Azure Cosmos DB data source. ウィザードの手順を進め、ターゲットのインデックス ページに移動すると、複合型のインデックスが表示されます。Further on in the wizard, when you get to the target index page, you'll see an index with complex types. このインデックスを作成して読み込み、クエリを実行して新しい構造を理解してください。Create and load this index, and then execute queries to understand the new structure.