.NET アプリケーションから Azure Search を使用する方法How to use Azure Search from a .NET Application

この記事では、 Azure Search .NET SDKを使用する手順について説明します。This article is a walkthrough to get you up and running with the Azure Search .NET SDK. .NET SDK を使用すると、Azure Search を使用してアプリケーションにリッチな検索エクスペリエンスを実装できます。You can use the .NET SDK to implement a rich search experience in your application using Azure Search.

Azure Search SDK の内容What's in the Azure Search SDK

SDK は、クライアント ライブラリ Microsoft.Azure.Searchで構成されます。The SDK consists of a client library, Microsoft.Azure.Search. SDK を使用すると、インデックス、データ ソース、インデクサーの管理、ドキュメントのアップロードと管理、クエリの実行を行うことができ、HTTP や JSON の細部を処理する必要はありません。It enables you to manage your indexes, data sources, and indexers, as well as upload and manage documents, and execute queries, all without having to deal with the details of HTTP and JSON.

クライアント ライブラリでは、IndexFieldDocument などのクラス、および SearchServiceClientSearchIndexClient クラス上の Indexes.CreateDocuments.Search などの操作が定義されています。The client library defines classes like Index, Field, and Document, as well as operations like Indexes.Create and Documents.Search on the SearchServiceClient and SearchIndexClient classes. これらのクラスは、次の名前空間にまとめられています。These classes are organized into the following namespaces:

Azure Search .NET SDK の最新バージョンが一般公開されました。The current version of the Azure Search .NET SDK is now generally available. 次のバージョンに組み込むためにフィードバックを提供する場合は、 フィードバック ページを使用してください。If you would like to provide feedback for us to incorporate in the next version, please visit our feedback page.

.NET SDK は、バージョン 2016-09-01Azure Search REST API をサポートします。The .NET SDK supports version 2016-09-01 of the Azure Search REST API. このバージョンでは、カスタム アナライザー、Azure BLOB インデクサー、Azure Table インデクサーがサポートされるようになりました。This version now includes support for custom analyzers and Azure Blob and Azure Table indexer support. JSON ファイルと CSV ファイルのインデックス作成のサポートなど、このバージョンに含まれていないプレビュー機能はプレビュー段階であり、4.0.1-preview バージョンの .NET SDK で提供されます。Preview features that are not part of this version, such as support for indexing JSON and CSV files, are in preview and available via 4.0.1-preview version of the .NET SDK.

この SDK では、Search サービスの作成とスケーリングや API キーの管理などの管理操作はサポートされていません。This SDK does not support Management Operations such as creating and scaling Search services and managing API keys. .NET アプリケーションから Search リソースを管理する必要がある場合は、Azure Search .NET Management SDK を使用できます。If you need to manage your Search resources from a .NET application, you can use the Azure Search .NET Management SDK.

最新バージョンの SDK へのアップグレードUpgrading to the latest version of the SDK

古いバージョンの Azure Search .NET SDK を既に使用しており、一般公開された新しいバージョンにアップグレードする場合、方法については この記事 をご覧ください。If you're already using an older version of the Azure Search .NET SDK and you'd like to upgrade to the new generally available version, this article explains how.

SDK の要件Requirements for the SDK

  1. Visual Studio 2017。Visual Studio 2017.
  2. 自分が所有する Azure Search サービス。Your own Azure 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. ポータルでの Azure Search サービスの作成 」は、これらの手順の参考になります。Create a service in the portal will help you through these steps.
  3. Visual Studio の [NuGet パッケージの管理] を使用して、Azure Search .NET SDK の NuGet パッケージ をダウンロードします。Download the Azure Search .NET SDK NuGet package by using "Manage NuGet Packages" in Visual Studio. NuGet.org でパッケージの名前 Microsoft.Azure.Search を検索してください。Just search for the package name Microsoft.Azure.Search on NuGet.org.

Azure Search .NET SDK は、.NET Framework 4.6 および .NET Core を対象とするアプリケーションをサポートします。The Azure Search .NET SDK supports applications targeting the .NET Framework 4.6 and .NET Core.

主要なシナリオCore scenarios

検索アプリケーションではいくつかの処理を実行する必要があります。There are several things you'll need to do in your search application. このチュートリアルではこれらの主要なシナリオについて説明します。In this tutorial, we'll cover these core scenarios:

  • インデックスの作成Creating an index
  • インデックスへのドキュメントの設定Populating the index with documents
  • フルテキスト検索およびフィルターを使用したドキュメントの検索Searching for documents using full-text search and filters

後のサンプル コードではこれらについて示します。The sample code that follows illustrates each of these. これらのコード スニペットを独自のアプリケーションに自由に使用してください。Feel free to use the code snippets in your own application.

OverviewOverview

これから説明するサンプル アプリケーションは、"hotels" という名前のインデックスを新しく作成し、いくつかのドキュメントをそこに格納してから、検索クエリを実行します。The sample application we'll be exploring creates a new index named "hotels", populates it with a few documents, then executes some search queries. 全体的な流れがわかるメイン プログラムを次に示します。Here 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();

    SearchServiceClient serviceClient = CreateSearchServiceClient(configuration);

    Console.WriteLine("{0}", "Deleting index...\n");
    DeleteHotelsIndexIfExists(serviceClient);

    Console.WriteLine("{0}", "Creating index...\n");
    CreateHotelsIndex(serviceClient);

    ISearchIndexClient indexClient = serviceClient.Indexes.GetClient("hotels");

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

    ISearchIndexClient indexClientForQueries = CreateSearchIndexClient(configuration);

    RunQueries(indexClientForQueries);

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

注意

このチュートリアルで使用したサンプル アプリケーションの完全なソース コードが GitHub にあります。You can find the full source code of the sample application used in this walk through on GitHub.

このプログラムの手順を詳しく見ていきましょう。We'll walk through this step by step. 最初に、新しい SearchServiceClientを作成する必要があります。First we need to create a new SearchServiceClient. このオブジェクトを使用してインデックスを管理できます。This object allows you to manage indexes. このオブジェクトを作成するには、Azure Search サービス名および管理 API キーを提供する必要があります。In order to construct one, you need to provide your Azure Search service name as well as an admin API key. この情報を、サンプル アプリケーションappsettings.json ファイルに入力できます。You can enter this information in the appsettings.json file of the sample application.

private static SearchServiceClient CreateSearchServiceClient(IConfigurationRoot configuration)
{
    string searchServiceName = configuration["SearchServiceName"];
    string adminApiKey = configuration["SearchServiceAdminApiKey"];

    SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(adminApiKey));
    return serviceClient;
}

注意

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

次の数行では、メソッドを呼び出して "hotels" という名前のインデックスを作成します。インデックスが既にある場合は最初に削除します。The next few lines call methods to create an index named "hotels", deleting it first if it already exists. これらのメソッドについては後で説明します。We will walk through these methods a little later.

Console.WriteLine("{0}", "Deleting index...\n");
DeleteHotelsIndexIfExists(serviceClient);

Console.WriteLine("{0}", "Creating index...\n");
CreateHotelsIndex(serviceClient);

次に、インデックスを設定する必要があります。Next, the index needs to be populated. そのためには、 SearchIndexClientが必要です。To do this, we will need a SearchIndexClient. これを取得するには、作成する方法と、SearchServiceClientIndexes.GetClient を呼び出す方法があります。There are two ways to obtain one: by constructing it, or by calling Indexes.GetClient on the SearchServiceClient. ここでは簡単な後者を使用します。We use the latter for convenience.

ISearchIndexClient indexClient = serviceClient.Indexes.GetClient("hotels");

注意

一般的な検索アプリケーションでは、インデックスの管理とインデックスの設定は、検索クエリとは別のコンポーネントによって処理されます。In a typical search application, index management and population is handled by a separate component from search queries. Indexes.GetClient は、別の SearchCredentials を指定する手間を省くため、インデックスを作成するのに便利です。Indexes.GetClient is convenient for populating an index because it saves you the trouble of providing another SearchCredentials. そのためには、SearchServiceClient を作成するときに使用した管理者キーを新しい SearchIndexClient に渡します。It does this by passing the admin key that you used to create the SearchServiceClient to the new SearchIndexClient. ただし、アプリケーションのクエリを実行する部分では、管理者キーの代わりにクエリ キーを渡すことができるように、 SearchIndexClient を直接作成する方が適しています。However, in the part of your application that executes queries, it is better to create the SearchIndexClient directly so that you can pass in a query key instead of an admin key. これは、最小権限の原則にも適合しており、アプリケーションのセキュリティ強化に役立ちます。This is consistent with the principle of least privilege and will help to make your application more secure. 管理者キーとクエリ キーの詳細については、 こちらを参照してください。You can find out more about admin keys and query keys here.

SearchIndexClientを作成したので、インデックスを設定できます。Now that we have a SearchIndexClient, we can populate the index. これは、後で説明する別のメソッドで行います。This is done by another method that we will walk through later.

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

最後に、検索クエリをいくつか実行し、結果を表示します。Finally, we execute a few search queries and display the results. 今回は別の SearchIndexClient を使用します。This time we use a different SearchIndexClient:

ISearchIndexClient indexClientForQueries = CreateSearchIndexClient(configuration);

RunQueries(indexClientForQueries);

RunQueries メソッドについては、後ほど詳しく説明します。We will take a closer look at the RunQueries method later. 新しい SearchIndexClient を作成するコードを次に示します。Here is the code to create the new SearchIndexClient:

private static SearchIndexClient CreateSearchIndexClient(IConfigurationRoot configuration)
{
    string searchServiceName = configuration["SearchServiceName"];
    string queryApiKey = configuration["SearchServiceQueryApiKey"];

    SearchIndexClient indexClient = new SearchIndexClient(searchServiceName, "hotels", new SearchCredentials(queryApiKey));
    return indexClient;
}

ここでは、インデックスへの書き込みアクセスは不要であるため、クエリ キーを使用します。This time we use a query key since we do not need write access to the index. この情報を、サンプル アプリケーションappsettings.json ファイルに入力できます。You can enter this information in the appsettings.json file of the sample application.

有効なサービス名と API キーを使用してこのアプリケーションを実行した場合、出力は次のようになります。If you run this application with a valid service name and API keys, the output should look like this:

Deleting index...

Creating index...

Uploading documents...

Waiting for documents to be indexed...

Search the entire index for the term 'budget' and return only the hotelName field:

Name: Roach Motel

Apply a filter to the index to find hotels cheaper than $150 per night, and return the hotelId and description:

ID: 2   Description: Cheapest hotel in town
ID: 3   Description: Close to town hall and the river

Search the entire index, order by a specific field (lastRenovationDate) in descending order, take the top two results, and show only hotelName and lastRenovationDate:

Name: Fancy Stay        Last renovated on: 6/27/2010 12:00:00 AM +00:00
Name: Roach Motel       Last renovated on: 4/28/1982 12:00:00 AM +00:00

Search the entire index for the term 'motel':

ID: 2   Base rate: 79.99        Description: Cheapest hotel in town     Description (French): Hôtel le moins cher en ville      Name: Roach Motel       Category: Budget        Tags: [motel, budget]   Parking included: yes   Smoking allowed: yes    Last renovated on: 4/28/1982 12:00:00 AM +00:00 Rating: 1/5     Location: Latitude 49.678581, longitude -122.131577

Complete.  Press any key to end application...

アプリケーションの完全なソース コードは、この記事の最後で提供します。The full source code of the application is provided at the end of this article.

次に、 Mainによって呼び出される各メソッドを詳しく見ていきます。Next, we will take a closer look at each of the methods called by Main.

インデックスの作成Creating an index

SearchServiceClient を作成した後、Main は次に、"hotels" インデックスが既に存在する場合はそれを削除します。After creating a SearchServiceClient, the next thing Main does is delete the "hotels" index if it already exists. この処理は次のメソッドで行います。That is done by the following method:

private static void DeleteHotelsIndexIfExists(SearchServiceClient serviceClient)
{
    if (serviceClient.Indexes.Exists("hotels"))
    {
        serviceClient.Indexes.Delete("hotels");
    }
}

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

注意

この記事のコード例では、わかりやすくするため、Azure Search .NET SDK の同期メソッドを使用します。The example code in this article uses the synchronous methods of the Azure Search .NET SDK for simplicity. 実際のアプリケーションでは、高い拡張性と応答性を維持するため、非同期メソッドを使用することをお勧めします。We recommend that you use the asynchronous methods in your own applications to keep them scalable and responsive. たとえば、上記のメソッドでは、ExistsDelete の代わりに、ExistsAsync および DeleteAsync を使用できます。For example, in the method above you could use ExistsAsync and DeleteAsync instead of Exists and Delete.

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

private static void CreateHotelsIndex(SearchServiceClient serviceClient)
{
    var definition = new Index()
    {
        Name = "hotels",
        Fields = FieldBuilder.BuildForType<Hotel>()
    };

    serviceClient.Indexes.Create(definition);
}

このメソッドは、新しいインデックスのスキーマを定義する Field オブジェクトのリストで新しい Index オブジェクトを作成します。This method creates a new Index object with a list of Field objects that defines the schema of the new index. 各フィールドには、名前、データ型、および検索動作を定義するいくつかの属性があります。Each field has a name, data type, and several attributes that define its search behavior. FieldBuilder クラスでは、リフレクションを使用して指定された Hotel モデル クラスのパブリック プロパティと属性を調べることで、インデックスの Field オブジェクトのリストを作成します。The FieldBuilder class uses reflection to create a list of Field 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.

注意

必要に応じて、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.

フィールドに加えて、スコアリング プロファイル、サジェスター、または CORS オプションを Index に追加することもできます (簡潔さを優先し、サンプルではこれらは省略されています)。In addition to fields, you can also add scoring profiles, suggesters, or CORS options to the Index (these are omitted from the sample for brevity). Index オブジェクトとその構成要素の詳細については、SDK リファレンスおよび Azure Search REST API リファレンスをご覧ください。You can find more information about the Index object and its constituent parts in the SDK reference, as well as in the Azure Search REST API reference.

インデックスの設定Populating the index

Main の次の手順では、新しく作成したインデックスを設定します。The next step in Main is to populate the newly-created index. この処理は次のメソッドで行います。This is done in the following method:

private static void UploadDocuments(ISearchIndexClient indexClient)
{
    var hotels = new Hotel[]
    {
        new Hotel()
        { 
            HotelId = "1", 
            BaseRate = 199.0, 
            Description = "Best hotel in town",
            DescriptionFr = "Meilleur hôtel en ville",
            HotelName = "Fancy Stay",
            Category = "Luxury", 
            Tags = new[] { "pool", "view", "wifi", "concierge" },
            ParkingIncluded = false, 
            SmokingAllowed = false,
            LastRenovationDate = new DateTimeOffset(2010, 6, 27, 0, 0, 0, TimeSpan.Zero), 
            Rating = 5, 
            Location = GeographyPoint.Create(47.678581, -122.131577)
        },
        new Hotel()
        { 
            HotelId = "2", 
            BaseRate = 79.99,
            Description = "Cheapest hotel in town",
            DescriptionFr = "Hôtel le moins cher en ville",
            HotelName = "Roach Motel",
            Category = "Budget",
            Tags = new[] { "motel", "budget" },
            ParkingIncluded = true,
            SmokingAllowed = true,
            LastRenovationDate = new DateTimeOffset(1982, 4, 28, 0, 0, 0, TimeSpan.Zero),
            Rating = 1,
            Location = GeographyPoint.Create(49.678581, -122.131577)
        },
        new Hotel() 
        { 
            HotelId = "3", 
            BaseRate = 129.99,
            Description = "Close to town hall and the river"
        }
    };

    var batch = IndexBatch.Upload(hotels);

    try
    {
        indexClient.Documents.Index(batch);
    }
    catch (IndexBatchException e)
    {
        // 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}",
            String.Join(", ", e.IndexingResults.Where(r => !r.Succeeded).Select(r => r.Key)));
    }

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

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

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

注意

この例では、単にドキュメントをアップロードします。In this example, we are just uploading documents. 既存のドキュメントに変更をマージする、またはドキュメントを削除する場合は、代わりに IndexBatch.MergeIndexBatch.MergeOrUpload、または IndexBatch.Delete を呼び出すことによってバッチを作成できます。If you wanted to merge changes into existing documents or delete documents, you could create batches by calling IndexBatch.Merge, IndexBatch.MergeOrUpload, or IndexBatch.Delete instead. IndexBatch.New を呼び出すことによって 1 つのバッチでさまざまな操作を組み合わせることもできます。これによって、IndexAction オブジェクトのコレクションを受け取り、各オブジェクトがドキュメントで特定の操作を実行するよう Azure Search に指示します。You can also mix different operations in a single batch by calling IndexBatch.New, which takes a collection of IndexAction objects, each of which tells Azure Search to perform a particular operation on a document. IndexAction.MergeIndexAction.Upload などの対応するメソッドを呼び出すことによって、独自の操作を行う IndexAction を作成できます。You can create each IndexAction with its own operation by calling the corresponding method such as IndexAction.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. Azure Search がバッチ内の一部のドキュメントのインデックス作成に失敗した場合、Documents.IndexIndexBatchException をスローします。If your Azure Search service fails to index some of the documents in the batch, an IndexBatchException is thrown by Documents.Index. サービスの負荷が高いときにドキュメントのインデックスを作成すると、これが発生する場合があります。This 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.

注意

FindFailedActionsToRetry メソッドを使用して、Index の前回の呼び出しで失敗したアクションだけを含む新しいバッチを作成できます。You can use the FindFailedActionsToRetry method to construct a new batch containing only the actions that failed in a previous call to Index. このメソッドについては、こちらをご覧ください。また、このメソッドの適切な使用方法については、StackOverflow をご覧ください。The method is documented here and there is a discussion of how to properly use it on StackOverflow.

最後に、UploadDocuments メソッドは 2 秒間遅延します。Finally, the UploadDocuments method delays for two seconds. インデックスの作成は Azure Search サービスで非同期的に行われるので、サンプル アプリケーションは短い時間待機して、確実にドキュメントを検索に使用できるようにする必要があります。Indexing happens asynchronously in your Azure 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.

.NET SDK がドキュメントを処理する方法How the .NET SDK handles documents

Azure Search .NET SDK が Hotel のようなユーザー定義クラスのインスタンスをどのようにしてインデックスにアップロードできるのか不思議に思われるかもしれません。You may be wondering how the Azure Search .NET SDK is able to upload instances of a user-defined class like Hotel to the index. その質問に答えるため、 Hotel クラスを見ていくことにします。To help answer that question, let's look at the Hotel class:

using System;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using Microsoft.Spatial;
using Newtonsoft.Json;

// The SerializePropertyNamesAsCamelCase attribute is defined in the Azure Search .NET SDK.
// It ensures that Pascal-case property names in the model class are mapped to camel-case
// field names in the index.
[SerializePropertyNamesAsCamelCase]
public partial class Hotel
{
    [System.ComponentModel.DataAnnotations.Key]
    [IsFilterable]
    public string HotelId { get; set; }

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

    [IsSearchable]
    public string Description { get; set; }

    [IsSearchable]
    [Analyzer(AnalyzerName.AsString.FrLucene)]
    [JsonProperty("description_fr")]
    public string DescriptionFr { get; set; }

    [IsSearchable, IsFilterable, IsSortable]
    public string HotelName { get; set; }

    [IsSearchable, IsFilterable, IsSortable, IsFacetable]
    public string Category { get; set; }

    [IsSearchable, IsFilterable, IsFacetable]
    public string[] Tags { get; set; }

    [IsFilterable, IsFacetable]
    public bool? ParkingIncluded { get; set; }

    [IsFilterable, IsFacetable]
    public bool? SmokingAllowed { get; set; }

    [IsFilterable, IsSortable, IsFacetable]
    public DateTimeOffset? LastRenovationDate { get; set; }

    [IsFilterable, IsSortable, IsFacetable]
    public int? Rating { get; set; }

    [IsFilterable, IsSortable]
    public GeographyPoint Location { get; set; }
}

最初に気付くのは、Hotel の各パブリック プロパティがインデックス定義のフィールドに対応していることですが、1 つ重要な違いがあります。各フィールドの名前が小文字で始まっているのに対し ("camel case")、Hotel の各パブリック プロパティの名前は大文字で始まっています ("Pascal case")。The first thing to notice is that each public property of Hotel corresponds to a field in the index definition, but with one crucial difference: The name of each field starts with a lower-case letter ("camel case"), while the name of each public property of Hotel starts with an upper-case letter ("Pascal case"). これは、ターゲット スキーマをアプリケーション開発者が制御できない場合にデータ バインドを実行する .NET アプリケーションでの一般的なシナリオです。This is a common scenario in .NET applications that perform data-binding where the target schema is outside the control of the application developer. プロパティ名を camel-case にして .NET の命名ガイドラインに違反するのではなく、プロパティ名を自動的に camel-case にマップするように [SerializePropertyNamesAsCamelCase] 属性で SDK に指示できます。Rather than having to violate the .NET naming guidelines by making property names camel-case, you can tell the SDK to map the property names to camel-case automatically with the [SerializePropertyNamesAsCamelCase] attribute.

注意

Azure Search .NET SDK は、 NewtonSoft JSON.NET ライブラリを使用して、カスタムのモデル オブジェクトから JSON 形式へのシリアル化や JSON 形式からの逆シリアル化を行います。The Azure Search .NET SDK uses the NewtonSoft JSON.NET library to serialize and deserialize your custom model objects to and from JSON. 必要に応じてこのシリアル化をカスタマイズできます。You can customize this serialization if needed. 詳細については、「JSON.NET 使用したシリアル化のカスタマイズ」をご覧ください。For more details, see Custom Serialization with JSON.NET.

次に注目すべき点は、各パブリック プロパティを装飾する IsFilterableIsSearchableKeyAnalyzer などの属性です。The second thing to notice are the attributes such as IsFilterable, IsSearchable, Key, and Analyzer that decorate each public property. これらの属性は、Azure Search インデックスの対応する属性に直接マップされます。These attributes map directly to the corresponding attributes of the Azure Search index. FieldBuilder クラスでは、これらの属性を使用してインデックスのフィールド定義を作成します。The FieldBuilder class uses these to construct field definitions for the index.

Hotel クラスに関する 3 番目の重要な点は、パブリック プロパティのデータ型です。The third important thing about the Hotel class are the data types of the public properties. これらのプロパティの .NET 型は、インデックス定義でそれらと同等のフィールド型にマップします。The .NET types of these 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 などの間にも、同じような型のマッピングがあります。型のマッピングの具体的なルールについては、Azure Search .NET SDK リファレンスDocuments.Get メソッドを参照してください。There are similar type mappings between bool? and Edm.Boolean, DateTimeOffset? and Edm.DateTimeOffset, etc. The specific rules for the type mapping are documented with the Documents.Get method in the Azure Search .NET SDK reference. FieldBuilder クラスは、このマッピングに自動的に対処しますが、シリアル化の問題のトラブルシューティングを行う必要がある場合に、マッピングを理解しておくと役立ちます。The FieldBuilder class takes care of this mapping for you, but it can still be helpful to understand in case you need to troubleshoot any serialization issues.

ドキュメントとして独自のクラスを使用するこの機能は、両方向で動作します。また、次のセクションで見るように、検索結果を取得し、SDK で自動的に任意の型に逆シリアル化することもできます。This ability to use your own classes as documents works in both directions; You can also retrieve search results and have the SDK automatically deserialize them to a type of your choice, as we will see in the next section.

注意

Azure Search .NET SDK は、Document クラスを使用して動的に型指定されたドキュメントもサポートします。これは、フィールドの値に対するフィールド名のキー/値マッピングです。The Azure Search .NET SDK also supports dynamically-typed documents using the Document class, which is a key/value mapping of field names to field values. この機能は、設計時にインデックス スキーマがわからない場合、または特定のモデル クラスにバインドすると不都合な場合に便利です。This is useful in scenarios where you don't know the index schema at design-time, or where it would be inconvenient to bind to specific model classes. ドキュメントを処理する SDK のすべてのメソッドには、Document クラスを使用するオーバーロード、およびジェネリック型パラメーターを使用する厳密な型指定のオーバーロードがあります。All the methods in the SDK that deal with documents have overloads that work with the Document class, as well as strongly-typed overloads that take a generic type parameter. このチュートリアルのサンプル コードでは、後者のみを使用しています。Only the latter are used in the sample code in this tutorial. Document クラスは Dictionary<string, object> から継承します。The Document class inherits from Dictionary<string, object>. その他の詳細については、こちらをご覧ください。You can find other details here.

null 許容のデータ型を使用する理由Why you should use nullable data types

Azure Search インデックスにマップする独自のモデル クラスを設計するときは、boolint などの値型のプロパティを null 許容型として宣言することをお勧めします (たとえば、bool ではなく bool? を使用する)。When designing your own model classes to map to an Azure Search index, we recommend declaring properties of value types such as bool and int to be nullable (for example, bool? instead of bool). null 非許容プロパティを使用する場合、対応するフィールドに null 値が含まれるドキュメントがインデックス内に存在しないことを、開発者が 保証する 必要があります。If you use a non-nullable property, you have to guarantee that no documents in your index contain a null value for the corresponding field. SDK または Azure Search サービスで、これを強制することはできません。Neither the SDK nor the Azure Search service will help you to enforce this.

これは単なる仮定上の問題ではありません。Edm.Int32 型の既存のインデックスに新しいフィールドを追加する場合を考えてみてください。This is not just a hypothetical concern: Imagine a scenario where you add a new field to an existing index that is of type Edm.Int32. インデックスの定義を更新した後、(Azure Search ではすべての型が null を許容するので) すべてのドキュメントでその新しいフィールドの値が null になります。After updating the index definition, all documents will have a null value for that new field (since all types are nullable in Azure Search). その後、そのフィールドが null 非許容型の int プロパティであるモデル クラスを使用した場合、ドキュメントを取得しようとすると、次のような JsonSerializationException が発生します。If you then use a model class with a non-nullable int property for that field, you will get a JsonSerializationException like this when trying to retrieve documents:

Error converting value {null} to type 'System.Int32'. Path 'IntValue'.

このため、ベスト プラクティスとして、モデル クラスでは null 許容型を使用することをお勧めします。For this reason, we recommend that you use nullable types in your model classes as a best practice.

JSON.NET 使用したシリアル化のカスタマイズCustom Serialization with JSON.NET

SDK では、ドキュメントのシリアル化と逆シリアル化に JSON.NET を使用します。The SDK uses JSON.NET for serializing and deserializing documents. 独自の JsonConverter または IContractResolver を定義して、必要に応じてシリアル化と逆シリアル化をカスタマイズできます (詳細については、「JSON.NET のドキュメント」をご覧ください)。You can customize serialization and deserialization if needed by defining your own JsonConverter or IContractResolver (see the JSON.NET documentation for more details). この機能は、アプリケーションの既存のモデル クラスを Azure Search 用に適合させる場合、およびその他の高度なシナリオに役立ちます。This can be useful when you want to adapt an existing model class from your application for use with Azure Search, and other more advanced scenarios. たとえば、カスタム シリアル化を使用すると次のことが可能です。For example, with custom serialization you can:

  • ドキュメント フィールドとして格納されるものに、モデル クラスの特定のプロパティを含める、または除外する。Include or exclude certain properties of your model class from being stored as document fields.
  • コードのプロパティ名とインデックスのフィールド名をマップする。Map between property names in your code and field names in your index.
  • ドキュメント フィールドへのプロパティのマッピングに使用できるカスタム属性を作成する。Create custom attributes that can be used for mapping properties to document fields.

Azure Search .NET SDK のユニット テストにカスタム シリアル化を実装する例については、GitHub を参照してください。You can find examples of implementing custom serialization in the unit tests for the Azure Search .NET SDK on GitHub. 手始めとしては、このフォルダーが適しています。A good starting point is this folder. カスタム シリアル化のテストに使用されるクラスが含まれます。It contains classes that are used by the custom serialization tests.

インデックス内のドキュメントの検索Searching for documents in the index

サンプル アプリケーションでは最後に、インデックス内のいくつかのドキュメントを検索します。The last step in the sample application is to search for some documents in the index. 次のメソッドがこれを行います。The following method does this:

private static void RunQueries(ISearchIndexClient indexClient)
{
    SearchParameters parameters;
    DocumentSearchResult<Hotel> results;

    Console.WriteLine("Search the entire index for the term 'budget' and return only the hotelName field:\n");

    parameters =
        new SearchParameters()
        {
            Select = new[] { "hotelName" }
        };

    results = indexClient.Documents.Search<Hotel>("budget", parameters);

    WriteDocuments(results);

    Console.Write("Apply a filter to the index to find hotels cheaper than $150 per night, ");
    Console.WriteLine("and return the hotelId and description:\n");

    parameters =
        new SearchParameters()
        {
            Filter = "baseRate lt 150",
            Select = new[] { "hotelId", "description" }
        };

    results = indexClient.Documents.Search<Hotel>("*", parameters);

    WriteDocuments(results);

    Console.Write("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");

    parameters =
        new SearchParameters()
        {
            OrderBy = new[] { "lastRenovationDate desc" },
            Select = new[] { "hotelName", "lastRenovationDate" },
            Top = 2
        };

    results = indexClient.Documents.Search<Hotel>("*", parameters);

    WriteDocuments(results);

    Console.WriteLine("Search the entire index for the term 'motel':\n");

    parameters = new SearchParameters();
    results = indexClient.Documents.Search<Hotel>("motel", parameters);

    WriteDocuments(results);
}

クエリを実行するたびに、このメソッドはまず新しい SearchParameters オブジェクトを作成します。Each time it executes a query, this method first creates a new SearchParameters object. このオブジェクトは、並べ替え、フィルター処理、ページング、ファセットなどの追加オプションをクエリに対して指定するために使用されます。This is used to specify additional options for the query such as sorting, filtering, paging, and faceting. このメソッドでは、さまざまなクエリの FilterSelectOrderByTop の各プロパティを設定します。In this method, we're setting the Filter, Select, OrderBy, and Top property for different queries. SearchParameters のすべてのプロパティについては、こちらをご覧ください。All the SearchParameters properties are documented here.

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

注意

検索クエリ式の構文の詳細については、こちらをご覧ください。You can find more information about the search query expression syntax here.

最後に、各クエリの実行後、このメソッドは検索結果のすべての一致を反復処理し、各ドキュメントをコンソールに出力します。Finally, after each query this method iterates through all the matches in the search results, printing each document to the console:

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

    Console.WriteLine();
}

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

parameters =
    new SearchParameters()
    {
        Select = new[] { "hotelName" }
    };

results = indexClient.Documents.Search<Hotel>("budget", parameters);

WriteDocuments(results);

この例では、"budget" という単語と一致するホテルを検索します。Select パラメーターで指定しているように、ホテル名だけを返します。In this case, we're searching for hotels that match the word "budget", and we want to get back only the hotel names, as specified by the Select parameter. 結果は次のとおりです。Here are the results:

Name: Roach Motel

次に、1 泊 150 ドル未満のホテルを検索し、ホテル ID と説明だけを返します。Next, we want to find the hotels with a nightly rate of less than $150, and return only the hotel ID and description:

parameters =
    new SearchParameters()
    {
        Filter = "baseRate lt 150",
        Select = new[] { "hotelId", "description" }
    };

results = indexClient.Documents.Search<Hotel>("*", parameters);

WriteDocuments(results);

このクエリでは、OData の $filter 式 (baseRate lt 150) を使用して、インデックス内のドキュメントをフィルター処理します。This query uses an OData $filter expression, baseRate lt 150, to filter the documents in the index. Azure Search がサポートする OData 構文の詳細については、 こちらを参照してください。You can find out more about the OData syntax that Azure Search supports here.

クエリの結果は次のとおりです。Here are the results of the query:

ID: 2   Description: Cheapest hotel in town
ID: 3   Description: Close to town hall and the river

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

parameters =
    new SearchParameters()
    {
        OrderBy = new[] { "lastRenovationDate desc" },
        Select = new[] { "hotelName", "lastRenovationDate" },
        Top = 2
    };

results = indexClient.Documents.Search<Hotel>("*", parameters);

WriteDocuments(results);

この例でも、OData 構文を使用して OrderBy パラメーターに lastRenovationDate desc を指定しています。In this case, we again use OData syntax to specify the OrderBy parameter as lastRenovationDate desc. また、上位 2 つのドキュメントだけを取得できるように、Top を 2 に設定しています。We also set Top to 2 to ensure we only get the top two documents. 前と同様に、Select を設定して返す必要があるフィールドを指定します。As before, we set Select to specify which fields should be returned.

結果は次のとおりです。Here are the results:

Name: Fancy Stay        Last renovated on: 6/27/2010 12:00:00 AM +00:00
Name: Roach Motel       Last renovated on: 4/28/1982 12:00:00 AM +00:00

最後に、"motel" という単語と一致するすべてのホテルを検索します。Finally, we want to find all hotels that match the word "motel":

parameters = new SearchParameters();
results = indexClient.Documents.Search<Hotel>("motel", parameters);

WriteDocuments(results);

結果は次のとおりです。Select プロパティを指定しなかったので、この結果にはすべてのフィールドが含まれています。And here are the results, which include all fields since we did not specify the Select property:

ID: 2   Base rate: 79.99        Description: Cheapest hotel in town     Description (French): Hôtel le moins cher en ville      Name: Roach Motel       Category: Budget        Tags: [motel, budget]   Parking included: yes   Smoking allowed: yes    Last renovated on: 4/28/1982 12:00:00 AM +00:00 Rating: 1/5     Location: Latitude 49.678581, longitude -122.131577

チュートリアルはここまでですが、ここで止めないでください。This step completes the tutorial, but don't stop here. 次のステップ では、Azure Search をさらに学習するための他のリソースを提供します。Next steps provides additional resources for learning more about Azure Search.

次のステップNext steps