管理 Azure Cosmos DB for MongoDB vCore 中的索引

适用对象: MongoDB vCore

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

重要

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

索引类型

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

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

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

{
  "_id": ObjectId("617a34e7a867530bff1b2346"),
  "title": "Azure Cosmos DB - A Game Changer",
  "content": "Azure Cosmos DB 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 Cosmos DB for MongoDB vCore 支持在以下位置创建索引:

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

以下命令会在字段 author 上创建单个字段索引,而后面的命令会在嵌入字段 firstName 上创建它。

use cosmicworks

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

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

在适用的情况下,一个查询可使用多个单字段索引。

注意

Azure Cosmos DB for MongoDB vCore 允许在集合上创建最多 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 Cosmos DB for MongoDB vCore 允许在多个字段的组合上创建文本索引,使你能够跨文档中的不同字段执行文本搜索。

配置文本索引选项

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

  • 创建一个索引,以支持对支持英语的 titlecontent 字段进行搜索。 此外,为 title 字段分配更高的权重,以在搜索结果中优先考虑它。

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

注意

当客户端使用“Cosmos DB”一词执行文本搜索查询时,将根据该词在“标题”和“内容”字段中是否存在和出现频率计算集合中每个文档的分数,由于“标题”字段的权重更高,因此向该字段分配的重要性更高。

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

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

  • 对短语 Cosmos DB 执行文本搜索。

    use cosmicworks
    
    db.products.find(
      { $text: { $search: "Cosmos DB" } }
    )
    
  • (可选)在查询中使用 $meta 投影运算符和 textScore 字段来查看权重

    use cosmicworks
    
    db.products.find(
    { $text: { $search: "Cosmos DB" } },
    { 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 Cosmos DB for MongoDB vCore 提供两种类型的地理空间索引:

  • 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. 当使用 geoNear 时,key 字段是必需的。

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

后续步骤