DocumentDB-インデックスレコード

デフォルトでは、DocumentDBは、ドキュメントがデータベースに追加されるとすぐに、ドキュメント内のすべてのプロパティに自動的にインデックスを付けます。ただし、インデックスを作成する必要のない特定のドキュメントやプロパティがある場合は、ストレージと処理のオーバーヘッドを削減する独自のインデックス作成ポリシーを制御および微調整できます。

DocumentDBにすべてのプロパティに自動的にインデックスを付けるように指示するデフォルトのインデックスポリシーは、多くの一般的なシナリオに適しています。ただし、インデックスを作成するものとインデックスを作成しないもの、およびインデックス作成に関するその他の機能を正確に制御するカスタムポリシーを実装することもできます。

DocumentDBは、次のタイプのインデックス作成をサポートしています-

  • Hash
  • Range

ハッシュ

ハッシュインデックスを使用すると、等しいかどうかを効率的にクエリできます。つまり、より小さい、より大きい、またはその間の値の範囲で一致するのではなく、特定のプロパティが正確な値に等しいドキュメントを検索します。

ハッシュインデックスを使用して範囲クエリを実行できますが、DocumentDBはハッシュインデックスを使用して一致するドキュメントを見つけることができず、代わりに各ドキュメントを順番にスキャンして、範囲クエリで選択する必要があるかどうかを判断する必要があります。

ハッシュインデックスのみを持つプロパティでORDERBY句を使用してドキュメントを並べ替えることはできません。

範囲

プロパティに定義された範囲インデックスであるDocumentDBを使用すると、値の範囲に対してドキュメントを効率的にクエリできます。また、ORDER BYを使用して、そのプロパティのクエリ結果を並べ替えることもできます。

DocumentDBを使用すると、任意またはすべてのプロパティでハッシュと範囲インデックスの両方を定義できます。これにより、効率的な等式クエリと範囲クエリ、およびORDERBYが可能になります。

インデックス作成ポリシー

すべてのコレクションには、すべてのドキュメントのすべてのプロパティの数値と文字列に使用されるインデックスのタイプを指定するインデックスポリシーがあります。

  • また、ドキュメントがコレクションに追加されるときに、ドキュメントが自動的にインデックスに登録されるかどうかを制御することもできます。

  • 自動インデックス作成はデフォルトで有効になっていますが、ドキュメントを追加するときにその動作をオーバーライドして、特定のドキュメントにインデックスを付けないようにDocumentDBに指示することができます。

  • 自動インデックス作成を無効にして、コレクションに追加されたときにデフォルトでドキュメントにインデックスが作成されないようにすることができます。同様に、これをドキュメントレベルで上書きし、コレクションに追加するときに特定のドキュメントにインデックスを付けるようにDocumentDBに指示できます。これは、手動インデックス付けとして知られています。

インデックスを含める/除外する

インデックス作成ポリシーでは、インデックスに含める、またはインデックスから除外するパスを定義することもできます。これは、クエリを実行することのないドキュメントの特定の部分と、クエリを実行する特定の部分があることがわかっている場合に役立ちます。

このような場合、コレクションに追加された各ドキュメントの特定の部分だけにインデックスを付けるようにDocumentDBに指示することで、インデックス作成のオーバーヘッドを減らすことができます。

自動インデックス作成

自動インデックス作成の簡単な例を見てみましょう。

Step 1 −最初に、自動インデックス作成と呼ばれるコレクションを作成します。ポリシーを明示的に指定せずに、このコレクションはデフォルトのインデックス作成ポリシーを使用します。つまり、このコレクションで自動インデックス作成が有効になります。

ここでは、データベースの自己リンクにIDベースのルーティングを使用しているため、コレクションを作成する前に、リソースIDを知ったりクエリを実行したりする必要はありません。mydbであるデータベースIDを使用できます。

Step 2 −次に、姓がUpstonの2つのドキュメントを作成しましょう。

private async static Task AutomaticIndexing(DocumentClient client) {
   Console.WriteLine();
   Console.WriteLine("**** Override Automatic Indexing ****");

   // Create collection with automatic indexing

   var collectionDefinition = new DocumentCollection {
      Id = "autoindexing"
   };
	
   var collection = await client.CreateDocumentCollectionAsync("dbs/mydb",
      collectionDefinition);

   // Add a document (indexed)
   dynamic indexedDocumentDefinition = new {
      id = "MARK",
      firstName = "Mark",
      lastName = "Upston",
      addressLine = "123 Main Street",
      city = "Brooklyn",
      state = "New York",
      zip = "11229",
   };
	
   Document indexedDocument = await client
      .CreateDocumentAsync("dbs/mydb/colls/autoindexing", indexedDocumentDefinition);
		
   // Add another document (request no indexing)
   dynamic unindexedDocumentDefinition = new {
      id = "JANE",
      firstName = "Jane",
      lastName = "Upston",
      addressLine = "123 Main Street",
      city = "Brooklyn",
      state = "New York",
      zip = "11229",
   };
	
   Document unindexedDocument = await client
      .CreateDocumentAsync("dbs/mydb/colls/autoindexing", unindexedDocumentDefinition,
      new RequestOptions { IndexingDirective = IndexingDirective.Exclude });

   //Unindexed document won't get returned when querying on non-ID (or selflink) property

   var doeDocs = client.CreateDocumentQuery("dbs/mydb/colls/autoindexing", "SELECT *
      FROM c WHERE c.lastName = 'Doe'").ToList();
		
   Console.WriteLine("Documents WHERE lastName = 'Doe': {0}", doeDocs.Count);

   // Unindexed document will get returned when using no WHERE clause

   var allDocs = client.CreateDocumentQuery("dbs/mydb/colls/autoindexing",
      "SELECT * FROM c").ToList();
   Console.WriteLine("All documents: {0}", allDocs.Count);
	
   // Unindexed document will get returned when querying by ID (or self-link) property
	
   Document janeDoc = client.CreateDocumentQuery("dbs/mydb/colls/autoindexing",
      "SELECT * FROM c WHERE c.id = 'JANE'").AsEnumerable().FirstOrDefault();
   Console.WriteLine("Unindexed document self-link: {0}", janeDoc.SelfLink);
	
   // Delete the collection
	
   await client.DeleteDocumentCollectionAsync("dbs/mydb/colls/autoindexing");
}

この最初のものは、Mark Upstonの場合、コレクションに追加され、デフォルトのインデックス付けポリシーに基づいてすぐに自動的にインデックス付けされます。

ただし、Mark Upstonの2番目のドキュメントが追加されると、コレクションのインデックス作成ポリシーにかかわらず、このドキュメントにインデックスを付けないようにDocumentDBに明示的に指示するIndexingDirective.Excludeを使用してリクエストオプションを渡しました。

最後に、両方のドキュメントに対してさまざまなタイプのクエリがあります。

Step 3 −CreateDocumentClientからAutomaticIndexingタスクを呼び出しましょう。

private static async Task CreateDocumentClient() {
   // Create a new instance of the DocumentClient 
   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) { 
      await AutomaticIndexing(client); 
   } 
}

上記のコードをコンパイルして実行すると、次の出力が返されます。

**** Override Automatic Indexing **** 
Documents WHERE lastName = 'Upston': 1 
All documents: 2 
Unindexed document self-link: dbs/kV5oAA==/colls/kV5oAOEkfQA=/docs/kV5oAOEkfQACA 
AAAAAAAAA==/

ご覧のとおり、このようなドキュメントは2つありますが、Markのドキュメントにはインデックスが付けられていないため、クエリはMarkのドキュメントのみを返します。コレクション内のすべてのドキュメントを取得するためにWHERE句を指定せずに再度クエリを実行すると、両方のドキュメントを含む結果セットが得られます。これは、インデックス付けされていないドキュメントが、WHERE句のないクエリによって常に返されるためです。

IDまたはセルフリンクでインデックス付けされていないドキュメントを取得することもできます。したがって、MarkのドキュメントをID MARKでクエリすると、コレクションでインデックスが作成されていなくても、DocumentDBがドキュメントを返すことがわかります。

手動インデックス作成

自動インデックス作成をオーバーライドすることによる手動インデックス作成の簡単な例を見てみましょう。

Step 1−まず、manualindexingというコレクションを作成し、自動インデックス作成を明示的に無効にすることでデフォルトのポリシーを上書きします。これは、特に要求がない限り、このコレクションに追加された新しいドキュメントはインデックスに登録されないことを意味します。

private async static Task ManualIndexing(DocumentClient client) {
   Console.WriteLine();
   Console.WriteLine("**** Manual Indexing ****");
   // Create collection with manual indexing

   var collectionDefinition = new DocumentCollection {
      Id = "manualindexing",
      IndexingPolicy = new IndexingPolicy {
         Automatic = false,
      },
   };
	
   var collection = await client.CreateDocumentCollectionAsync("dbs/mydb",
      collectionDefinition);
		
   // Add a document (unindexed)
   dynamic unindexedDocumentDefinition = new {
      id = "MARK",
      firstName = "Mark",
      lastName = "Doe",
      addressLine = "123 Main Street",
      city = "Brooklyn",
      state = "New York",
      zip = "11229",
   }; 
	
   Document unindexedDocument = await client
      .CreateDocumentAsync("dbs/mydb/colls/manualindexing", unindexedDocumentDefinition);
  
   // Add another document (request indexing)
   dynamic indexedDocumentDefinition = new {
      id = "JANE",
      firstName = "Jane",
      lastName = "Doe",
      addressLine = "123 Main Street",
      city = "Brooklyn",
      state = "New York",
      zip = "11229",
   };
	
   Document indexedDocument = await client.CreateDocumentAsync
      ("dbs/mydb/colls/manualindexing", indexedDocumentDefinition, new RequestOptions {
      IndexingDirective = IndexingDirective.Include });

   //Unindexed document won't get returned when querying on non-ID (or selflink) property

   var doeDocs = client.CreateDocumentQuery("dbs/mydb/colls/manualindexing",
      "SELECT * FROM c WHERE c.lastName = 'Doe'").ToList();
   Console.WriteLine("Documents WHERE lastName = 'Doe': {0}", doeDocs.Count);
	
   // Unindexed document will get returned when using no WHERE clause
	
   var allDocs = client.CreateDocumentQuery("dbs/mydb/colls/manualindexing",
      "SELECT * FROM c").ToList();
   Console.WriteLine("All documents: {0}", allDocs.Count);
	
   // Unindexed document will get returned when querying by ID (or self-link) property
	
   Document markDoc = client
      .CreateDocumentQuery("dbs/mydb/colls/manualindexing",
      "SELECT * FROM c WHERE c.id = 'MARK'")
      .AsEnumerable().FirstOrDefault();
   Console.WriteLine("Unindexed document self-link: {0}", markDoc.SelfLink);
   await client.DeleteDocumentCollectionAsync("dbs/mydb/colls/manualindexing");
}

Step 2−ここで、以前と同じ2つのドキュメントを再度作成します。コレクションのインデックス作成ポリシーにより、このドキュメントはインデックスに登録されないため、今回はMarkのドキュメントに特別なリクエストオプションを提供しません。

Step 3 − Markに2番目のドキュメントを追加するとき、IndexingDirective.IncludeでRequestOptionsを使用して、このドキュメントにインデックスを付ける必要があることをDocumentDBに通知します。これにより、コレクションのインデックスポリシーを上書きする必要があります。

最後に、両方のドキュメントに対してさまざまなタイプのクエリがあります。

Step 4 −CreateDocumentClientからManualIndexingタスクを呼び出しましょう。

private static async Task CreateDocumentClient() {
   // Create a new instance of the DocumentClient 
   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
      await ManualIndexing(client); 
   } 
}

上記のコードをコンパイルして実行すると、次の出力が表示されます。

**** Manual Indexing **** 
Documents WHERE lastName = 'Upston': 1 
All documents: 2 
Unindexed document self-link: dbs/kV5oAA==/colls/kV5oANHJPgE=/docs/kV5oANHJPgEBA 
AAAAAAAAA==/

この場合も、クエリは2つのドキュメントのうち1つだけを返しますが、今回は、明示的にインデックスを作成するように要求したJaneDoeを返します。ただし、以前と同様に、WHERE句を指定せずにクエリを実行すると、Markのインデックス付けされていないドキュメントを含め、コレクション内のすべてのドキュメントが取得されます。IDでインデックス付けされていないドキュメントをクエリすることもできます。これは、インデックスが作成されていなくてもDocumentDBが返します。