📜  DocumentDB-索引记录

📅  最后修改于: 2020-11-28 13:50:05             🧑  作者: Mango


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

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

DocumentDB支持以下类型的索引-

  • 杂凑
  • 范围

杂凑

哈希索引可实现对相等性的高效查询,即在搜索给定属性等于确切值的文档时,而不是在小于,大于或之间的一系列值上进行匹配。

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

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

范围

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

DocumentDB允许您在任何或所有属性上定义哈希和范围索引,从而实现高效的相等性和范围查询以及ORDER BY。

索引政策

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

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

  • 默认情况下会启用自动索引编制,但是您可以在添加文档时覆盖该行为,告诉DocumentDB不要为该特定文档编制索引。

  • 您可以禁用自动索引编制,以便在默认情况下将文档添加到集合时不编制索引。同样,您可以在文档级别覆盖它,并指示DocumentDB在将特定文档添加到集合时为其建立索引。这称为手动索引。

包含/排除索引

索引策略还可以定义应在索引中包括或排除哪些路径。如果您知道文档中某些部分是您从未查询过的,而某些部分是您要做的,则这很有用。

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

自动索引

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

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

在这里,我们使用基于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或自我链接来检索它们。因此,当我们通过Mark的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添加第二个文档时,我们使用带有IndexingDirective.Include的RequestOptions来告诉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也会返回该ID。