在 Azure DocumentDB 中管理索引

索引是通过提供对集合中字段的快速访问来提高数据检索速度的结构。 它们的工作原理是创建指向数据的有序指针集,通常基于键字段。 Azure DocumentDB 利用多个上下文中的索引,包括查询下推、唯一约束和分片。

重要

“_id”字段是唯一一个默认被索引的字段,字段的最大大小可以是 。 建议基于查询筛选器和谓词添加其他索引,以优化性能。

索引类型

为简单起见,让我们考虑一个具有以下设置的博客应用程序示例:

  • 数据库名称cosmicworks
  • 集合名称products

此示例应用程序将文章存储为具有以下结构的文档。 引用的所有示例进一步利用此集合的结构。

{
  "_id": ObjectId("617a34e7a867530bff1b2346"),
  "title": "Azure DocumentDB - A Game Changer",
  "content": "Azure DocumentDB is a globally distributed, multi-model database service.",
  "author": {lastName: "Doe", firstName: "John"},
  "category": "Technology",
  "launchDate": ISODate("2024-06-24T10:08:20.000Z"),
  "published": true
}

单个字段索引

单个字段索引存储集合中单个字段的信息。 单个字段索引的排序顺序无关紧要。 _id 字段默认保持索引。

Azure DocumentDB 支持创建以下索引

  • 顶级文档字段。
  • 嵌入的文档。
  • 嵌入文档中的字段。

以下命令在字段 author 上创建单个字段索引,以下命令在嵌入字段上创建该索引 firstName

use cosmicworks

db.products.createIndex({"author": 1})

// indexing embedded property
db.products.createIndex({"author.firstName": -1})

一个查询可以使用多个可用字段索引。

注释

Azure DocumentDB 允许对集合创建最多 64 个索引。 根据层的不同,我们可以根据请求计划最多 300 个索引的扩展。

复合索引

复合索引通过允许基于文档中的多个字段进行高效 查询和排序 来提高数据库性能。 这种优化减少了扫描整个集合、加快数据检索和组织的需求。

以下命令为字段 authorlaunchDate 创建方向相反的复合索引。

use cosmicworks

db.products.createIndex({"author":1, "launchDate":-1})

Order 的字段会影响索引的选择性或利用率。 查询 find 不会利用创建的索引。

use cosmicworks

db.products.find({"launchDate": {$gt: ISODate("2024-06-01T00:00:00.000Z")}})

局限性

  • 复合索引中最多 32 个字段\路径。

部分索引

具有关联查询筛选器的索引,用于描述何时在索引中生成术语。

use cosmicworks

db.products.createIndex (
   { "author": 1, "launchDate": 1 },
   { partialFilterExpression: { "launchDate": { $gt: ISODate("2024-06-24T10:08:20.000Z") } } }
)

局限性

  • 部分索引不支持 ORDER BYUNIQUE,除非筛选器符合条件。

文本索引

文本索引是优化基于文本的查询的特殊数据结构,使其更快、更高效。

使用createIndex方法和text选项在title字段上创建文本索引。

use cosmicworks;

db.products.createIndex({ title: "text" })

注释

虽然每个集合只能定义一个文本索引,但 Azure DocumentDB 允许基于多个字段的组合创建文本索引,使你能够在文档中的不同字段中执行文本搜索。

配置文本索引选项

Azure DocumentDB 中的文本索引附带多个选项来自定义其行为。 例如,可以指定文本分析的语言、设置权重以确定某些字段的优先级,以及配置不区分大小写的搜索。 下面是使用选项创建文本索引的示例:

  • 创建支持英语语言搜索的索引,用于titlecontent字段的搜索。 此外,为 title 字段分配更高的权重,以在搜索结果中确定其优先级。

    use cosmicworks
    
    db.products.createIndex(
        { title: "text", content: "text" },
        { default_language: "english", weights: { title: 10, content: 5 }, caseSensitive: false }
    )
    

注释

当客户端使用术语“DocumentDB”执行文本搜索查询时,集合中每个文档的分数将基于“title”和“content”字段中字词的状态和频率进行计算,因为“title”字段的权重较高。

使用文本索引执行文本搜索

创建文本索引后,可以在查询中使用“text”运算符执行文本搜索。 文本运算符采用搜索字符串,并将其与文本索引匹配以查找相关文档。

  • 对短语 DocumentDB执行文本搜索。

    use cosmicworks
    
    db.products.find(
      { $text: { $search: "DocumentDB" } }
    )
    
  • 可选地,将 $meta 投影运算符与查询中的 textScore 字段一起使用,以查看权重

    use cosmicworks
    
    db.products.find(
    { $text: { $search: "DocumentDB" } },
    { score: { $meta: "textScore" } }
    )
    

局限性

  • 一个集合上只能定义一个文本索引。
  • 排序作不能在 MongoDB 中使用文本索引的顺序。
  • Hint() 函数不支持与使用 $text 表达式的查询结合使用。
  • 与其他索引类型相比,文本索引可能相对较大,占用大量存储空间。

通配符索引

在单个字段上建立索引,对 field 下的所有路径进行索引,但不包括同一级别的其他字段。 例如,对于以下示例文档

{
 "children":
    {
     "familyName": "Merriam",
     "pets": { "details": {“name”: "Goofy", ”age”: 3} }
   } 
}

在 { “pets.$**” 上创建索引: 1 },创建详细信息和子文档属性的索引,但不在“familyName”上创建索引。

局限性

  • 通配符索引不支持唯一索引。
  • 通配符索引不支持将 ORDER BY 向下推送,除非筛选器中仅包含通配符中已有的路径(因为它们不为未定义的元素建立索引)。
  • 复合通配符索引只能有 one 通配符术语和 one 或更多索引项。 { "pets.$**": 1, “familyName”: 1 }

空间索引

地理空间索引支持对作为 GeoJSON 对象或旧坐标对存储的数据进行查询。 可以使用地理空间索引来提高对地理空间数据的查询或运行某些地理空间查询的性能。

Azure DocumentDB 提供两种类型的地理空间索引:

  • 2dsphere 索引,它支持解释球体上的几何图形的查询。
  • 2d 索引,支持在平面上解释几何图形的查询。

2D 索引

2d 索引仅支持旧的坐标对样式用于存储地理空间数据。

使用 createIndex 方法和 2d 选项在 location 字段上创建地理空间索引。

db.places.createIndex({ "location": "2d"});

局限性

  • 只有 one 位置字段可以成为索引的 2d 一部分,只有 one 其他非地理空间字段才能成为索引的 compound 2d 一部分 db.places.createIndex({ "location": "2d", "non-geospatial-field": 1 / -1 })

2dsphere 索引

2dsphere 索引支持类似地球的球体上的地理空间查询。 它可以支持 GeoJSON 对象或旧坐标对。 2dSphere 索引处理存储数据的 GeoJSON 样式,如果遇到旧点,则它将转换为 GeoJSON 点。

使用 createIndex 方法和 2dsphere 选项在 location 字段上创建地理空间索引。

db.places.createIndex({ "location": "2dsphere"});

2dsphere 索引允许对多个地理空间和多个非地理空间数据字段创建索引。 db.places.createIndex({ "location": "2d", "non-geospatial-field": 1 / -1, ... "more non-geospatial-field": 1 / -1 })

局限性

  • 不支持使用常规索引和地理空间索引的复合索引。 创建任一地理空间索引将导致错误。

    // Compound Regular & 2dsphere indexes are not supported yet
    db.collection.createIndex({a: 1, b: "2dsphere"})
    
    // Compound 2d indexes are not supported yet
    db.collection.createIndex({a: "2d", b: 1})
    
  • 带孔的多边形不起作用。 插入带孔的多边形没有限制,但 $geoWithin 查询在某些场景中会失败。

    1. 如果查询本身具有带孔的多边形

      coll.find(
        {
            "b": {
                "$geoWithin": {
                    "$geometry": {
                        "coordinates": [
                            [
                                [ 0, 0], [0, 10], [10, 10],[10,0],[0, 0]
                            ],
                            [
                                [5, 5], [8, 5], [ 8, 8], [ 5, 8], [ 5, 5]
                            ]
                        ],
                        "type": "Polygon"
                    }
                }
            }
        })
      
      // MongoServerError: $geoWithin currently doesn't support polygons with holes
      
    2. 如果有任何包含带孔多边形的未筛选文档。

      [mongos] test> coll.find()
        [
          {
            _id: ObjectId("667bf7560b4f1a5a5d71effa"),
            b: {
              type: 'Polygon',
              coordinates: [
                [ [ 0, 0 ], [ 0, 10 ], [ 10, 10 ], [ 10, 0 ], [ 0, 0 ] ],
                [ [ 5, 5 ], [ 8, 5 ], [ 8, 8 ], [ 5, 8 ], [ 5, 5 ] ]
              ]
            }
          }
        ]
      // MongoServerError: $geoWithin currently doesn't support polygons with holes
      
    3. 使用 key 时,geoNear 字段是必填的。

       [mongos] test> coll.aggregate([{ $geoNear: { $near: { "type": "Point", coordinates: [0, 0] } } }])
      
       // MongoServerError: $geoNear requires a 'key' option as a String
      

后续步骤