DocumentDB - 索引记录



默认情况下,DocumentDB 会在文档添加到数据库后立即自动为文档中的每个属性建立索引。但是,您可以进行控制并微调自己的索引策略,在某些特定文档和/或属性不需要建立索引时,减少存储和处理开销。

告诉 DocumentDB 自动为每个属性建立索引的默认索引策略适用于许多常见场景。但是,您也可以实现自定义策略,对要索引的内容和不索引的内容进行精确控制,以及其他与索引相关的功能。

DocumentDB 支持以下类型的索引:

  • 哈希
  • 范围

哈希

哈希索引能够有效地查询相等性,即在搜索给定属性等于精确值的文档时,而不是匹配一系列值(如小于、大于或介于)。

您可以使用哈希索引执行范围查询,但 DocumentDB 将无法使用哈希索引查找匹配的文档,而需要依次扫描每个文档以确定是否应通过范围查询选择它。

您将无法使用 ORDER BY 子句对仅具有哈希索引的属性排序文档。

范围

为属性定义的范围索引,DocumentDB 允许对一系列值有效地查询文档。它还允许您使用 ORDER BY 对该属性上的查询结果进行排序。

DocumentDB 允许您在任何或所有属性上同时定义哈希索引和范围索引,这使得能够有效地进行相等性和范围查询,以及 ORDER BY。

索引策略

每个集合都有一个索引策略,该策略规定在每个文档的每个属性的数字和字符串中使用哪种类型的索引。

  • 您还可以控制文档在添加到集合时是否自动建立索引。

  • 自动索引默认启用,但在添加文档时可以覆盖此行为,告诉 DocumentDB 不要索引该特定文档。

  • 您可以禁用自动索引,以便默认情况下,文档在添加到集合时不会被索引。类似地,您可以在文档级别覆盖此设置,并在将文档添加到集合时指示 DocumentDB 对其进行索引。这称为手动索引。

包含/排除索引

索引策略还可以定义应包含在索引中或排除在索引之外的路径或路径。如果您知道文档的某些部分从未被查询过,而某些部分却被查询过,则此功能很有用。

在这些情况下,您可以通过告诉 DocumentDB 只索引添加到集合的每个文档的这些特定部分来减少索引开销。

自动索引

让我们来看一个自动索引的简单示例。

步骤 1 - 首先,我们创建一个名为 autoindexing 的集合,并且没有显式提供策略,此集合使用默认索引策略,这意味着在此集合上启用了自动索引。

这里我们使用基于 ID 的路由进行数据库自链接,因此我们不需要知道它的资源 ID 或在创建集合之前查询它。我们只需使用数据库 ID,即 mydb。

步骤 2 - 现在让我们创建两个文档,两个文档的姓氏都是 Upston。

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 添加第二个文档时,我们已将请求选项与 IndexingDirective.Exclude 一起传递,该选项明确指示 DocumentDB 不要索引此文档,尽管集合的索引策略是如此。

最后,我们对这两个文档有不同类型的查询。

步骤 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==/

如您所见,我们有两个这样的文档,但查询仅返回 Mark 的文档,因为 Mark 的文档未建立索引。如果我们再次查询,不带 WHERE 子句来检索集合中的所有文档,那么我们将获得一个包含两个文档的结果集,这是因为未建立索引的文档始终由没有 WHERE 子句的查询返回。

我们还可以通过其 ID 或自链接检索未建立索引的文档。因此,当我们通过其 ID MARK 查询 Mark 的文档时,我们看到 DocumentDB 返回了该文档,即使它未在集合中建立索引。

手动索引

让我们来看一个通过覆盖自动索引来进行手动索引的简单示例。

步骤 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");
}

步骤 2 - 现在我们将再次创建与之前相同的两个文档。这次我们将不对 Mark 的文档提供任何特殊的请求选项,因为根据集合的索引策略,此文档将不会被索引。

步骤 3 - 现在,当我们添加 Mark 的第二个文档时,我们使用 RequestOptions 和 IndexingDirective.Include 来告诉 DocumentDB 它应该索引此文档,这将覆盖集合的索引策略(该策略指出不应索引此文档)。

最后,我们对这两个文档有不同类型的查询。

步骤 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==/

同样,查询仅返回两个文档中的一个,但这次它返回 Jane Doe,这是我们明确要求建立索引的。但与之前一样,不带 WHERE 子句的查询将检索集合中的所有文档,包括 Mark 的未建立索引的文档。我们还可以通过其 ID 查询未建立索引的文档,DocumentDB 会返回它,即使它未建立索引。

广告