C# .NET アプリケーションで Azure.Search.Documents を使用する方法How to use Azure.Search.Documents in a C# .NET Application

この記事では、C# および Azure.Search.Documents (バージョン 11) クライアント ライブラリを使用して検索オブジェクトを作成および管理する方法について説明します。This article explains how to create and manage search objects using C# and the Azure.Search.Documents (version 11) client library.

バージョン 11 についてAbout version 11

Azure SDK for .NET には、Azure SDK チームからの新しい Azure.Search.Documents クライアント ライブラリが追加されています。これは Microsoft.Azure.Search クライアント ライブラリと機能的に同等ですが、必要に応じて一般的な方法と規約が利用されます。Azure SDK for .NET adds a new Azure.Search.Documents client library from the Azure SDK team that is functionally equivalent to Microsoft.Azure.Search client libraries, but utilizes common approaches and conventions where applicable. 例としては、AzureKeyCredential キー認証と、JSON シリアル化のための System.Text.Json.Serialization があります。Some examples include AzureKeyCredential key authentication, and System.Text.Json.Serialization for JSON serialization.

以前のバージョンと同様に、このライブラリを使用して次のことができます。As with previous versions, you can use this library to:

  • 検索インデックス、データ ソース、インデクサー、スキルセット、シノニム マップの作成と管理Create and manage search indexes, data sources, indexers, skillsets, and synonym maps
  • インデックスでの検索ドキュメントの読み込みと管理Load and manage search documents in an index
  • HTTP や JSON の詳細を処理する必要がない、クエリの実行Execute queries, all without having to deal with the details of HTTP and JSON

このライブラリは、単一の Azure.Search.Document NuGet パッケージとして配布されます。これには、検索サービスへのプログラムによるアクセスに使用するすべての API が含まれます。The library is distributed as a single Azure.Search.Documents NuGet package, which includes all APIs used for programmatic access to a search service.

クライアント ライブラリでは、SearchIndexSearchFieldSearchDocument などのクラス、および SearchIndexClientSearchClient クラス上の SearchIndexClient.CreateIndexSearchClient.Search などの操作が定義されています。The client library defines classes like SearchIndex, SearchField, and SearchDocument, as well as operations like SearchIndexClient.CreateIndex and SearchClient.Search on the SearchIndexClient and SearchClient classes. これらのクラスは、次の名前空間にまとめられています。These classes are organized into the following namespaces:

Azure.Search.Documents (バージョン 11) は、Azure Cognitive Search REST API のバージョン 2020-06-30 を対象としています。Azure.Search.Documents (version 11) targets version 2020-06-30 of the Azure Cognitive Search REST API.

このクライアント ライブラリには、検索サービスの作成とスケーリングや API キーの管理などのサービス管理操作は用意されていません。The client library does not provide service management operations, such as creating and scaling search services and managing API keys. .NET アプリケーションから検索リソースを管理する必要がある場合は、Azure SDK for .NET の Microsoft.Azure.Management.Search ライブラリを使用します。If you need to manage your search resources from a .NET application, use the Microsoft.Azure.Management.Search library in the Azure SDK for .NET.

v11 へのアップグレードUpgrade to v11

以前のバージョンの .NET SDK を使用していて、現在一般公開されているバージョンにアップグレードする場合は、「Azure Cognitive Search .NET SDK バージョン 11 へのアップグレード」を参照してください。If you have been using the previous version of the .NET SDK and you'd like to upgrade to the current generally available version, see Upgrade to Azure Cognitive Search .NET SDK version 11

SDK の要件SDK requirements

  • Visual Studio 2019 以降。Visual Studio 2019 or later.

  • 自分が所有する Azure Cognitive Search サービス。Your own Azure Cognitive Search service. SDK を使用するには、サービスの名前および 1 つまたは複数の API キーが必要です。In order to use the SDK, you will need the name of your service and one or more API keys. ポータルでサービスを作成していない場合は、作成します。Create a service in the portal if you don't have one.

  • Visual Studio の [ツール] > [NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] を使用して、Azure.Search.Documents package をダウンロードします。Download the Azure.Search.Documents package using Tools > NuGet Package Manager > Manage NuGet Packages for Solution in Visual Studio. パッケージ名 Azure.Search.Documents を検索します。Search for the package name Azure.Search.Documents.

Azure SDK for .NET は .NET Standard 2.0 に準拠しています。これは、.NET Framework 4.6.1 と .NET Core 2.0 を最小要件としていることを意味します。Azure SDK for .NET conforms to .NET Standard 2.0, which means .NET Framework 4.6.1 and .NET Core 2.0 as minimum requirements.

サンプル アプリケーションExample application

"例を使って説明する" この記事では、GitHub の DotNetHowTo コード例を使用して、Azure Cognitive Search の基本的な概念を説明します。具体的には、検索インデックスの作成、読み込み、クエリを実行する方法です。This article "teaches by example", relying on the DotNetHowTo code example on GitHub to illustrate fundamental concepts in Azure Cognitive Search - specifically, how to create, load, and query a search index.

この記事の残りの部分では、"hotels" という名前の新しいインデックスがあり、いくつかのドキュメントが表示され、結果に一致するいくつかのクエリが作成されているものとします。For the rest of this article, assume a new index named "hotels", populated with a few documents, with several queries that match on results.

全体的な流れがわかるメイン プログラムを次に示します。Below is the main program, showing the overall flow:

// This sample shows how to delete, create, upload documents and query an index
static void Main(string[] args)
{
    IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
    IConfigurationRoot configuration = builder.Build();

    SearchIndexClient indexClient = CreateSearchIndexClient(configuration);

    string indexName = configuration["SearchIndexName"];

    Console.WriteLine("{0}", "Deleting index...\n");
    DeleteIndexIfExists(indexName, indexClient);

    Console.WriteLine("{0}", "Creating index...\n");
    CreateIndex(indexName, indexClient);

    SearchClient searchClient = indexClient.GetSearchClient(indexName);

    Console.WriteLine("{0}", "Uploading documents...\n");
    UploadDocuments(searchClient);

    SearchClient indexClientForQueries = CreateSearchClientForQueries(indexName, configuration);

    Console.WriteLine("{0}", "Run queries...\n");
    RunQueries(indexClientForQueries);

    Console.WriteLine("{0}", "Complete.  Press any key to end application...\n");
    Console.ReadKey();
}

有効なサービス名と API キーを使用してこのアプリケーションを実行したと想定すると、出力は次の部分的なスクリーンショットのようになります。Next is a partial screenshot of the output, assuming you run this application with a valid service name and API keys:

サンプル プログラムからの Console.WriteLine 出力

クライアントの種類Client types

クライアント ライブラリの場合、さまざまな操作に 3 種類のクライアントを使用します。SearchIndexClient はインデックスの作成、更新、または削除、SearchClient はインデックスの読み込みまたはクエリ実行、SearchIndexerClient はインデクサーとスキルセットの操作に使用します。The client library uses three client types for various operations: SearchIndexClient to create, update, or delete indexes, SearchClient to load or query an index, and SearchIndexerClient to work with indexers and skillsets. この記事では、最初の 2 つを中心に説明します。This article focuses on the first two.

すべてのクライアントには、少なくとも、サービス名またはエンドポイントと API キーが必要です。At a minimum, all of the clients require the service name or endpoint, and an API key. この情報は、構成ファイル内に指定するのが一般的です。これは、DotNetHowTo サンプル アプリケーションappsettings.json ファイル内にあるものと同様です。It's common to provide this information in a configuration file, similar to what you find in the appsettings.json file of the DotNetHowTo sample application. 構成ファイルから読み取るには、プログラムに using Microsoft.Extensions.Configuration; を追加します。To read from the configuration file, add using Microsoft.Extensions.Configuration; to your program.

インデックスの作成、更新、または削除に使用するインデックス クライアントを次のステートメントで作成します。The following statement creates the index client used to create, update, or delete indexes. これによって検索エンドポイントと管理 API キーが取得されます。It takes a search endpoint and admin API key.

private static SearchIndexClient CreateSearchIndexClient(IConfigurationRoot configuration)
{
    string searchServiceEndPoint = configuration["SearchServiceEndPoint"];
    string adminApiKey = configuration["SearchServiceAdminApiKey"];

    SearchIndexClient indexClient = new SearchIndexClient(new Uri(searchServiceEndPoint), new AzureKeyCredential(adminApiKey));
    return indexClient;
}

次のステートメントで、ドキュメントの読み込みまたはクエリの実行に使用する検索クライアントを作成します。The next statement creates the search client used to load documents or run queries. SearchClient にはインデックスが必要です。SearchClient requires an index. ドキュメントを読み込むには管理者 API キーが必要ですが、クエリの実行はクエリ API キーを使用してできます。You will need an admin API key to load documents, but you can use a query API key to run queries.

string indexName = configuration["SearchIndexName"];

private static SearchClient CreateSearchClientForQueries(string indexName, IConfigurationRoot configuration)
{
    string searchServiceEndPoint = configuration["SearchServiceEndPoint"];
    string queryApiKey = configuration["SearchServiceQueryApiKey"];

    SearchClient searchClient = new SearchClient(new Uri(searchServiceEndPoint), indexName, new AzureKeyCredential(queryApiKey));
    return searchClient;
}

注意

インポート操作に対して無効なキー (たとえば、管理者キーが必要なときにクエリ キーなど) を提供すると、操作メソッドを初めて呼び出したときに、SearchClient によって CloudException がスローされ、エラー メッセージ "アクセス不可" が表示されます。If you provide an invalid key for the import operation (for example, a query key where an admin key was required), the SearchClient will throw a CloudException with the error message "Forbidden" the first time you call an operation method on it. このような場合は、API キーを再確認してください。If this happens to you, double-check the API key.

インデックスを削除するDeleting the index

開発の初期段階では、更新された定義を使用して作成し直すことができるように、進行中のインデックスを削除するために DeleteIndex ステートメントを含めることをお勧めします。In the early stages of development, you might want to include a DeleteIndex statement to delete a work-in-progress index so that you can recreate it with an updated definition. Azure Cognitive Search のサンプル コードには、多くの場合、サンプルを再実行できるように削除手順が含まれています。Sample code for Azure Cognitive Search often includes a deletion step so that you can re-run the sample.

次の行によって DeleteIndexIfExists が呼び出されます。The following line calls DeleteIndexIfExists:

Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, indexClient);

このメソッドは、指定した SearchIndexClient を使用してインデックスが存在するかどうかを確認し、存在する場合は、それを削除します。This method uses the given SearchIndexClient to check if the index exists, and if so, deletes it:

private static void DeleteIndexIfExists(string indexName, SearchIndexClient indexClient)
{
    try
    {
        if (indexClient.GetIndex(indexName) != null)
        {
            indexClient.DeleteIndex(indexName);
        }
    }
    catch (RequestFailedException e) when (e.Status == 404)
    {
        // Throw an exception if the index name isn't found
        Console.WriteLine("The index doesn't exist. No deletion occurred.");

注意

この記事のコード例では、わかりやすくするために同期メソッドを使用していますが、実際のアプリケーションでは、拡張性と応答性を維持するために非同期メソッドを使用してください。The example code in this article uses the synchronous methods for simplicity, but you should use the asynchronous methods in your own applications to keep them scalable and responsive. たとえば、上記のメソッドでは、DeleteIndex の代わりに、DeleteIndexAsync を使用できます。For example, in the method above you could use DeleteIndexAsync instead of DeleteIndex.

インデックスを作成するCreate an index

SearchIndexClient を使用してインデックスを作成できます。You can use SearchIndexClient to create an index.

次のメソッドは、新しいインデックスのスキーマを定義する SearchField オブジェクトのリストを使用して新しい SearchIndex オブジェクトを作成します。The method below creates a new SearchIndex object with a list of SearchField objects that define the schema of the new index. 各フィールドには、名前、データ型、および検索動作を定義するいくつかの属性があります。Each field has a name, data type, and several attributes that define its search behavior.

フィールドは、FieldBuilder を使用してモデル クラスから定義できます。Fields can be defined from a model class using FieldBuilder. FieldBuilder クラスでは、リフレクションを使用して指定された Hotel モデル クラスのパブリック プロパティと属性を調べることで、インデックスの SearchField オブジェクトのリストを作成します。The FieldBuilder class uses reflection to create a list of SearchField objects for the index by examining the public properties and attributes of the given Hotel model class. Hotel クラスについては、後ほど詳しく説明します。We'll take a closer look at the Hotel class later on.

private static void CreateIndex(string indexName, SearchIndexClient indexClient)
{
    FieldBuilder fieldBuilder = new FieldBuilder();
    var searchFields = fieldBuilder.Build(typeof(Hotel));

    var definition = new SearchIndex(indexName, searchFields);

    indexClient.CreateOrUpdateIndex(definition);
}

フィールド以外に、スコアリング プロファイル、サジェスター、または CORS オプションもインデックスに追加できます (簡潔にするために、これらのパラメーターはサンプルから省略されています)。Besides fields, you could also add scoring profiles, suggesters, or CORS options to the index (these parameters are omitted from the sample for brevity). SearchIndex オブジェクトとその構成要素の詳細については、SearchIndex プロパティ リストと、REST API リファレンスを参照してください。You can find more information about the SearchIndex object and its constituent parts in the SearchIndex properties list, as well as in the REST API reference.

注意

必要に応じて、FieldBuilder を使用するのではなく、Field オブジェクトのリストをいつでも直接作成できます。You can always create the list of Field objects directly instead of using FieldBuilder if needed. たとえば、モデル クラスを使用しない場合や、属性を追加して変更するのは望ましくない既存のモデル クラスを使用する必要がある場合などです。For example, you may not want to use a model class or you may need to use an existing model class that you don't want to modify by adding attributes.

Main() で CreateIndex を呼び出すCall CreateIndex in Main()

上記のメソッドを呼び出すことによって、Main は新しい "hotels" インデックスを作成します。Main creates a new "hotels" index by calling the above method:

Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, indexClient);

データ表現にモデル クラスを使用するUse a model class for data representation

DotNetHowTo サンプルでは、HotelAddressRoom の各データ構造にモデル クラスを使用しています。The DotNetHowTo sample uses model classes for the Hotel, Address, and Room data structures. Hotel は単一レベルの複合型 (マルチパート フィールド) である Address と、Room (マルチパート フィールドのコレクション) を参照します。Hotel references Address, a single level complex type (a multi-part field), and Room (a collection of multi-part fields).

これらの型を使用して、インデックスの作成と読み込み、およびクエリからの応答の構造化を行うことができます。You can use these types to create and load the index, and to structure the response from a query:

// Use-case: <Hotel> in a field definition
FieldBuilder fieldBuilder = new FieldBuilder();
var searchFields = fieldBuilder.Build(typeof(Hotel));

// Use-case: <Hotel> in a response
private static void WriteDocuments(SearchResults<Hotel> searchResults)
{
    foreach (SearchResult<Hotel> result in searchResults.GetResults())
    {
        Console.WriteLine(result.Document);
    }

    Console.WriteLine();
}

別の方法として、インデックスにフィールドを直接追加する方法もあります。An alternative approach is to add fields to an index directly. 次の例では、いくつかのフィールドのみを示します。The following example shows just a few fields.

 SearchIndex index = new SearchIndex(indexName)
 {
     Fields =
         {
             new SimpleField("hotelId", SearchFieldDataType.String) { IsKey = true, IsFilterable = true, IsSortable = true },
             new SearchableField("hotelName") { IsFilterable = true, IsSortable = true },
             new SearchableField("hotelCategory") { IsFilterable = true, IsSortable = true },
             new SimpleField("baseRate", SearchFieldDataType.Int32) { IsFilterable = true, IsSortable = true },
             new SimpleField("lastRenovationDate", SearchFieldDataType.DateTimeOffset) { IsFilterable = true, IsSortable = true }
         }
 };

フィールド定義Field definitions

.NET のデータ モデルおよびその対応するインデックス スキーマは、エンド ユーザーに提供する検索エクスペリエンスをサポートしている必要があります。Your data model in .NET and its corresponding index schema should support the search experience you'd like to give to your end user. .NET の最上位レベル オブジェクト (検索インデックス内の検索ドキュメントなど) はそれぞれ、ユーザー インターフェイスで示される検索結果に対応します。Each top level object in .NET, such as a search document in a search index, corresponds to a search result you would present in your user interface. たとえば、ホテル検索アプリケーションで、エンド ユーザーは、ホテル名、ホテルの機能、または特定の部屋の特徴で検索することができます。For example, in a hotel search application your end users may want to search by hotel name, features of the hotel, or the characteristics of a particular room.

フィールドは、使用方法を決定するデータ型と属性によって各クラス内に定義されます。Within each class, a field is defined with a data type and attributes that determine how it's used. 各クラス内の各パブリック プロパティの名前は、インデックス定義内の同じ名前を持つフィールドにマップされます。The name of each public property in each class maps to a field with the same name in the index definition.

Hotel クラスから複数のフィールド定義を取得する次のスニペットを見てみましょう。Take a look at the following snippet that pulls several field definitions from the Hotel class. Address と Rooms は独自のクラス定義を持つ C# 型であることに注意してください (確認するには、サンプル コードを参照してください)。Notice that Address and Rooms are C# types with their own class definitions (refer to the sample code if you want to view them). 両方とも複合型です。Both are complex types. 詳細については、複合型のモデル化の方法に関するページを参照してください。For more information, see How to model complex types.

public partial class Hotel
{
    [SimpleField(IsKey = true, IsFilterable = true)]
    public string HotelId { get; set; }

    [SearchableField(IsSortable = true)]
    public string HotelName { get; set; }

    [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
    public string Description { get; set; }

    [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
    public string Category { get; set; }

    [JsonIgnore]
    public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;

    [SearchableField]
    public Address Address { get; set; }

    public Room[] Rooms { get; set; }

フィールド クラスを選択するChoosing a field class

フィールドを定義するときは、SearchField 基底クラスを使用することも、プロパティが事前に構成された "テンプレート" として機能する派生ヘルパー モデルを使用することもできます。When defining fields, you can use the base SearchField class, or you can use derivative helper models that serve as "templates", with pre-configured properties.

インデックス内の厳密に 1 つのフィールドが、ドキュメント キー (IsKey = true) として機能する必要があります。Exactly one field in your index must serve as the document key (IsKey = true). これは文字列でなければならず、各ドキュメントを一意に識別する必要があります。It must be a string, and it must uniquely identify each document. また、IsHidden = true を使用している必要があります。これは、検索結果に表示できないことを意味します。It's also required to have IsHidden = true, which means it cannot be visible in search results.

フィールドの種類Field type 説明と使用方法Description and usage
SearchField ほとんどのプロパティが null に設定された基底クラス (必須の Name と、既定で標準の Lucene になる AnalyzerName は除く)。Base class, with most properties set to null, excepting Name which is required, and AnalyzerName which defaults to standard Lucene.
SimpleField ヘルパー モデル。Helper model. 任意のデータ型にすることができます。また、常に検索不可能 (フルテキスト検索クエリでは無視される) で、取得可能 (非表示ではない) となります。Can be any data type, is always non-searchable (it's ignored for full text search queries), and is retrievable (it's not hidden). その他の属性は、既定ではオフですが、有効にすることができます。Other attributes are off by default, but can be enabled. SimpleField は、フィルター、ファセット、スコアリング プロファイルでのみ使用されるフィールドやドキュメント ID での使用が考えられます。You might use a SimpleField for document IDs or fields used only in filters, facets, or scoring profiles. その場合は必ず、シナリオに必要な属性を適用してください (ドキュメント ID の IsKey = true など)。If so, be sure to apply any attributes that are necessary for the scenario, such as IsKey = true for a document ID. 詳細については、ソース コードの SimpleFieldAttribute.cs を参照してください。For more information, see SimpleFieldAttribute.cs in source code.
SearchableField ヘルパー モデル。Helper model. 文字列であることが必要です。常に検索可能で、取得可能となります。Must be a string, and is always searchable and retrievable. その他の属性は、既定ではオフですが、有効にすることができます。Other attributes are off by default, but can be enabled. 検索可能なタイプのフィールドであるため、同意語がサポートされるほか、アナライザーのプロパティがすべてサポートされます。Because this field type is searchable, it supports synonyms and the full complement of analyzer properties. 詳細については、ソース コードの SearchableFieldAttribute.cs を参照してください。For more information, see the SearchableFieldAttribute.cs in source code.

基本 SearchField API を使用する場合も、そのいずれかのヘルパー モデルを使用する場合も、フィルター、ファセット、並べ替えの属性は明示的に有効にする必要があります。Whether you use the basic SearchField API or either one of the helper models, you must explicitly enable filter, facet, and sort attributes. たとえば、IsFilterableIsSortableIsFacetable の各属性は、上のサンプルのように明示的に指定する必要があります。For example, IsFilterable, IsSortable, and IsFacetable must be explicitly attributed, as shown in the sample above.

フィールド属性を追加するAdding field attributes

各フィールドが IsFilterableIsSortableIsKeyAnalyzerName などの属性で装飾されていることに注意してください。Notice how each field is decorated with attributes such as IsFilterable, IsSortable, IsKey, and AnalyzerName. これらの属性は、Azure Cognitive Search インデックス内の対応するフィールド属性に直接マップされます。These attributes map directly to the corresponding field attributes in an Azure Cognitive Search index. FieldBuilder クラスは、これらのプロパティを使用してインデックスのフィールド定義を構築します。The FieldBuilder class uses these properties to construct field definitions for the index.

フィールド型のマッピングField type mapping

プロパティの .NET 型は、インデックス定義でそれらと同等のフィールド型にマップされます。The .NET types of the properties map to their equivalent field types in the index definition. たとえば、Category 文字列プロパティは、Edm.String 型の category フィールドにマップします。For example, the Category string property maps to the category field, which is of type Edm.String. bool?Edm.BooleanDateTimeOffset?Edm.DateTimeOffset などの間にも、同じような型のマッピングがあります。There are similar type mappings between bool?, Edm.Boolean, DateTimeOffset?, and Edm.DateTimeOffset and so on.

SmokingAllowed プロパティを見つけてしまいましたか?Did you happen to notice the SmokingAllowed property?

[JsonIgnore]
public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;

このプロパティの JsonIgnore 属性によって、フィールドとしてインデックスにシリアル化しないよう、FieldBuilder に指示が与えられます。The JsonIgnore attribute on this property tells the FieldBuilder to not serialize it to the index as a field. これは、ご利用のアプリケーションでヘルパーとして使用できる、クライアント側の計算されたプロパティを作成する優れた方法です。This is a great way to create client-side calculated properties you can use as helpers in your application. この場合、SmokingAllowed プロパティは、Rooms コレクション内に喫煙可能な Room があるかどうかを反映します。In this case, the SmokingAllowed property reflects whether any Room in the Rooms collection allows smoking. すべて false の場合、ホテル全館で喫煙できないことを示します。If all are false, it indicates that the entire hotel does not allow smoking.

インデックスを読み込むLoad an index

Main の次の手順で、新しく作成した "hotels" インデックスを設定します。The next step in Main populates the newly-created "hotels" index. このインデックス設定は、次のメソッドで実行されます。(説明のため "..." で置き換えられた一部のコード。This index population is done in the following method: (Some code replaced with "..." for illustration purposes. 完全なデータ生成コードに対する完全なサンプル ソリューションを参照してください。)See the full sample solution for the full data population code.)

private static void UploadDocuments(SearchClient searchClient)
{
    IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create(
        IndexDocumentsAction.Upload(
            new Hotel()
            {
                HotelId = "1",
                HotelName = "Secret Point Motel",
                ...
                Address = new Address()
                {
                    StreetAddress = "677 5th Ave",
                    ...
                },
                Rooms = new Room[]
                {
                    new Room()
                    {
                        Description = "Budget Room, 1 Queen Bed (Cityside)",
                        ...
                    },
                    new Room()
                    {
                        Description = "Budget Room, 1 King Bed (Mountain View)",
                        ...
                    },
                    new Room()
                    {
                        Description = "Deluxe Room, 2 Double Beds (City View)",
                        ...
                    }
                }
            }),
        IndexDocumentsAction.Upload(
            new Hotel()
            {
                HotelId = "2",
                HotelName = "Twin Dome Motel",
                ...
                {
                    StreetAddress = "140 University Town Center Dr",
                    ...
                },
                Rooms = new Room[]
                {
                    new Room()
                    {
                        Description = "Suite, 2 Double Beds (Mountain View)",
                        ...
                    },
                    new Room()
                    {
                        Description = "Standard Room, 1 Queen Bed (City View)",
                        ...
                    },
                    new Room()
                    {
                        Description = "Budget Room, 1 King Bed (Waterfront View)",
                        ...
                    }
                }
            }),
        IndexDocumentsAction.Upload(
            new Hotel()
            {
                HotelId = "3",
                HotelName = "Triple Landscape Hotel",
                ...
                Address = new Address()
                {
                    StreetAddress = "3393 Peachtree Rd",
                    ...
                },
                Rooms = new Room[]
                {
                    new Room()
                    {
                        Description = "Standard Room, 2 Queen Beds (Amenities)",
                        ...
                    },
                    new Room ()
                    {
                        Description = "Standard Room, 2 Double Beds (Waterfront View)",
                        ...
                    },
                    new Room()
                    {
                        Description = "Deluxe Room, 2 Double Beds (Cityside)",
                        ...
                    }
                }
            }
        };

    try
    {
        IndexDocumentsResult result = searchClient.IndexDocuments(batch);
    }
    catch (Exception)
    {
        // Sometimes when your Search service is under load, indexing will fail for some of the documents in
        // the batch. Depending on your application, you can take compensating actions like delaying and
        // retrying. For this simple demo, we just log the failed document keys and continue.
        Console.WriteLine("Failed to index some of the documents: {0}");
    }

    Console.WriteLine("Waiting for documents to be indexed...\n");
    Thread.Sleep(2000);

このメソッドには 4 つの部分があります。This method has four parts. 最初の部分では、インデックスにアップロードする入力データとして使用される、3 つの Hotel オブジェクトと、それぞれに含まれる 3 つの Room オブジェクトの配列を作成します。The first creates an array of 3 Hotel objects each with 3 Room objects that will serve as our input data to upload to the index. このデータは、わかりやすくするためハードコーディングされています。This data is hard-coded for simplicity. 実際のアプリケーションでは、データは SQL Database などの外部データ ソースから取得されます。In an actual application, data will likely come from an external data source such as a SQL database.

2 番目の部分では、ドキュメントを含む IndexDocumentsBatch を作成します。The second part creates an IndexDocumentsBatch containing the documents. この場合は IndexDocumentsAction.Upload を呼び出すことによって、作成時にバッチに適用する操作を指定します。You specify the operation you want to apply to the batch at the time you create it, in this case by calling IndexDocumentsAction.Upload. その後、バッチは IndexDocuments メソッドによって Azure Cognitive Search インデックスにアップロードされます。The batch is then uploaded to the Azure Cognitive Search index by the IndexDocuments method.

注意

この例では、単にドキュメントをアップロードします。In this example, we are just uploading documents. 既存のドキュメントに変更をマージする、またはドキュメントを削除する場合は、代わりに IndexDocumentsAction.MergeIndexDocumentsAction.MergeOrUpload、または IndexDocumentsAction.Delete を呼び出すことによってバッチを作成できます。If you wanted to merge changes into existing documents or delete documents, you could create batches by calling IndexDocumentsAction.Merge, IndexDocumentsAction.MergeOrUpload, or IndexDocumentsAction.Delete instead. IndexBatch.New を呼び出すことによって 1 つのバッチでさまざまな操作を組み合わせることもできます。これによって、IndexDocumentsAction オブジェクトのコレクションを受け取り、各オブジェクトがドキュメントで特定の操作を実行するよう Azure Cognitive Search に指示します。You can also mix different operations in a single batch by calling IndexBatch.New, which takes a collection of IndexDocumentsAction objects, each of which tells Azure Cognitive Search to perform a particular operation on a document. IndexDocumentsAction.MergeIndexAction.Upload などの対応するメソッドを呼び出すことによって、独自の操作を行う IndexDocumentsAction を作成できます。You can create each IndexDocumentsAction with its own operation by calling the corresponding method such as IndexDocumentsAction.Merge, IndexAction.Upload, and so on.

このメソッドの 3 番目の部分は、インデックス作成の重要なエラー ケースを処理する catch ブロックです。The third part of this method is a catch block that handles an important error case for indexing. 検索サービスでバッチ内の一部のドキュメントのインデックス作成に失敗した場合、IndexDocuments から IndexBatchException がスローされます。If your search service fails to index some of the documents in the batch, an IndexBatchException is thrown by IndexDocuments. この例外は、サービスの負荷が高いときにドキュメントのインデックスを作成していると発生する場合があります。This exception can happen if you are indexing documents while your service is under heavy load. コードでこのケースを明示的に処理することを強くお勧めします。We strongly recommend explicitly handling this case in your code. しばらく待ってから失敗したドキュメントのインデックス作成を再試行したり、サンプルと同じようにログに記録してから続けることができます。または、アプリケーションのデータ整合性要件に応じて他の処理を行うこともできます。You can delay and then retry indexing the documents that failed, or you can log and continue like the sample does, or you can do something else depending on your application's data consistency requirements.

最後に、UploadDocuments メソッドは 2 秒間遅延します。Finally, the UploadDocuments method delays for two seconds. インデックスの作成は検索サービスで非同期的に行われるので、サンプル アプリケーションは短い時間待機して、確実にドキュメントを検索に使用できるようにする必要があります。Indexing happens asynchronously in your search service, so the sample application needs to wait a short time to ensure that the documents are available for searching. 通常、このような遅延は、デモ、テスト、およびサンプル アプリケーションでのみ必要です。Delays like this are typically only necessary in demos, tests, and sample applications.

Main() で UploadDocuments を呼び出すCall UploadDocuments in Main()

次のコード スニペットでは、indexClient の GetSearchClient メソッドを使用して、SearchClient のインスタンスを設定します。The following code snippet sets up an instance of SearchClient using the GetSearchClient method of indexClient. indexClient で、ドキュメントの読み込みまたは更新に必要な管理 API キーをその要求に対して使用します。The indexClient uses an admin API key on its requests, which is required for loading or refreshing documents.

別の方法として、SearchClient を直接呼び出し、AzureKeyCredential で管理者 API キーを渡します。An alternate approach is to call SearchClient directly, passing in an admin API key on AzureKeyCredential.

SearchClient searchClient = indexClient.GetSearchClient(indexName);

Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(searchClient);

クエリを実行するRun queries

まず、appsettings.json から検索エンドポイントとクエリ API キーを読み取る SearchClient を設定します。First, set up a SearchClient that reads the search endpoint and query API key from appsettings.json:

private static SearchClient CreateSearchClientForQueries(string indexName, IConfigurationRoot configuration)
{
    string searchServiceEndPoint = configuration["SearchServiceEndPoint"];
    string queryApiKey = configuration["SearchServiceQueryApiKey"];

    SearchClient searchClient = new SearchClient(new Uri(searchServiceEndPoint), indexName, new AzureKeyCredential(queryApiKey));
    return searchClient;
}

次に、クエリ要求を送信するメソッドを定義します。Second, define a method that sends a query request.

メソッドでクエリが実行されるたびに、新しい SearchOptions オブジェクトが作成されます。Each time the method executes a query, it creates a new SearchOptions object. このオブジェクトは、並べ替え、フィルター処理、ページング、ファセットなどの、クエリへの追加オプションを指定するために使用されます。This object is used to specify additional options for the query such as sorting, filtering, paging, and faceting. このメソッドで、さまざまなクエリの FilterSelectOrderBy の各プロパティを設定します。In this method, we're setting the Filter, Select, and OrderBy property for different queries. 検索クエリ式の構文の詳細については、単純なクエリ構文のページを参照してください。For more information about the search query expression syntax, Simple query syntax.

次の手順では、検索クエリを実際に実行します。The next step is to actually execute the search query. この検索は、SearchClient.Search メソッドを使用して実行されます。Running the search is done using the SearchClient.Search method. 各クエリでは、使用する検索テキストを文字列として (または、検索テキストがない場合は "*" を) 渡し、以前に作成した検索オプションも渡します。For each query, pass the search text to use as a string (or "*" if there is no search text), plus the search options created earlier. また、SearchClient.Search に対する型パラメーターとして Hotel も指定します。これは、検索結果のドキュメントを Hotel 型のオブジェクトに逆シリアル化するように SDK に指示します。We also specify Hotel as the type parameter for SearchClient.Search, which tells the SDK to deserialize documents in the search results into objects of type Hotel.

private static void RunQueries(SearchClient searchClient)
{
    SearchOptions options;
    SearchResults<Hotel> results;

    Console.WriteLine("Query 1: Search for 'motel'. Return only the HotelName in results:\n");

    options = new SearchOptions();
    options.Select.Add("HotelName");

    results = searchClient.Search<Hotel>("motel", options);

    WriteDocuments(results);

    Console.Write("Query 2: Apply a filter to find hotels with rooms cheaper than $100 per night, ");
    Console.WriteLine("returning the HotelId and Description:\n");

    options = new SearchOptions()
    {
        Filter = "Rooms/any(r: r/BaseRate lt 100)"
    };
    options.Select.Add("HotelId");
    options.Select.Add("Description");

    results = searchClient.Search<Hotel>("*", options);

    WriteDocuments(results);

    Console.Write("Query 3: Search the entire index, order by a specific field (lastRenovationDate) ");
    Console.Write("in descending order, take the top two results, and show only hotelName and ");
    Console.WriteLine("lastRenovationDate:\n");

    options =
        new SearchOptions()
        {
            Size = 2
        };
    options.OrderBy.Add("LastRenovationDate desc");
    options.Select.Add("HotelName");
    options.Select.Add("LastRenovationDate");

    results = searchClient.Search<Hotel>("*", options);

    WriteDocuments(results);

    Console.WriteLine("Query 4: Search the HotelName field for the term 'hotel':\n");

    options = new SearchOptions();
    options.SearchFields.Add("HotelName");

    //Adding details to select, because "Location" is not supported yet when deserialize search result to "Hotel"
    options.Select.Add("HotelId");
    options.Select.Add("HotelName");
    options.Select.Add("Description");
    options.Select.Add("Category");
    options.Select.Add("Tags");
    options.Select.Add("ParkingIncluded");
    options.Select.Add("LastRenovationDate");
    options.Select.Add("Rating");
    options.Select.Add("Address");
    options.Select.Add("Rooms");

    results = searchClient.Search<Hotel>("hotel", options);

    WriteDocuments(results);
}

第 3 に、応答を書き込み、各ドキュメントをコンソールに出力するメソッドを定義します。Third, define a method that writes the response, printing each document to the console:

private static void WriteDocuments(SearchResults<Hotel> searchResults)
{
    foreach (SearchResult<Hotel> result in searchResults.GetResults())
    {
        Console.WriteLine(result.Document);
    }

    Console.WriteLine();
}

Main() で RunQueries を呼び出すCall RunQueries in Main()

SearchClient indexClientForQueries = CreateSearchClientForQueries(indexName, configuration);

Console.WriteLine("{0}", "Running queries...\n");
RunQueries(indexClientForQueries);

クエリのコンストラクトを調べるExplore query constructs

各クエリについて詳しく見ていきましょう。Let's take a closer look at each of the queries in turn. 最初のクエリを実行するコードを次に示します。Here is the code to execute the first query:

options = new SearchOptions();
options.Select.Add("HotelName");

results = searchClient.Search<Hotel>("motel", options);

WriteDocuments(results);

この例では、検索可能なあらゆるフィールドで "motel" という単語のインデックス全体を検索し、Select オプションによって指定されるとおり、ホテル名だけを返します。In this case, we're searching the entire index for the word "motel" in any searchable field and we only want to retrieve the hotel names, as specified by the Select option. 結果は次のようになります。Here are the results:

Name: Secret Point Motel

Name: Twin Dome Motel

2 番目のクエリで、フィルターを使用して 1 泊 100 ドル未満の部屋を選択します。In the second query, use a filter to select room with a nightly rate of less than $100. 結果にホテルの ID と説明のみを返します。Return only the hotel ID and description in the results:

options = new SearchOptions()
{
    Filter = "Rooms/any(r: r/BaseRate lt 100)"
};
options.Select.Add("HotelId");
options.Select.Add("Description");

results = searchClient.Search<Hotel>("*", options);

上記のクエリでは、OData の $filter 式 (Rooms/any(r: r/BaseRate lt 100)) を使用して、インデックス内のドキュメントをフィルター処理しています。The above query uses an OData $filter expression, Rooms/any(r: r/BaseRate lt 100), to filter the documents in the index. ここでは、あらゆる演算子を使用して、'BaseRate lt 100' をルーム コレクションのすべての項目に適用します。This uses the any operator to apply the 'BaseRate lt 100' to every item in the Rooms collection. 詳細については、OData のフィルター構文のページを参照してください。For more information, see OData filter syntax.

3 番目のクエリで、最近改装された上位 2 つのホテルを検索し、ホテル名と最終改装日を表示します。In the third query, find the top two hotels that have been most recently renovated, and show the hotel name and last renovation date. 次にコードを示します。Here is the code:

options =
    new SearchOptions()
    {
        Size = 2
    };
options.OrderBy.Add("LastRenovationDate desc");
options.Select.Add("HotelName");
options.Select.Add("LastRenovationDate");

results = searchClient.Search<Hotel>("*", options);

WriteDocuments(results);

最後のクエリで、"hotel" という単語に一致するすべてのホテル名を検索します。In the last query, find all hotels names that match the word "hotel":

options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Description");
options.Select.Add("Category");
options.Select.Add("Tags");
options.Select.Add("ParkingIncluded");
options.Select.Add("LastRenovationDate");
options.Select.Add("Rating");
options.Select.Add("Address");
options.Select.Add("Rooms");

results = searchClient.Search<Hotel>("hotel", options);

WriteDocuments(results);

.NET SDK の概要についての説明はこのセクションが最後ですが、これで終わりにしないでください。This section concludes this introduction to the .NET SDK, but don't stop here. 次のセクションでは、Azure Cognitive Search を使用したプログラミングの詳細について学ぶためのリソースを示します。The next section suggests additional resources for learning more about programming with Azure Cognitive Search.

次のステップNext steps