在 Azure Cosmos DB for MongoDB vCore 中创建通配符索引

适用对象: MongoDB vCore

架构中包含不可预知字段集的工作负载可以使用通配符索引来支持针对任意或未知字段的查询,以优化性能。

通配符索引在以下方案中非常有用:

  • 对文档中任何字段进行筛选的查询,这使得通过单个命令对所有字段编制索引比单独为每个字段编制索引更容易。
  • 对文档中大多数字段进行筛选的查询,这使得通过单个命令对除少数几个字段以外的所有字段编制索引比单独为大多数字段编制索引更简单。

为所有字段编制索引

设置通配符索引,以方便查询所有可能的文档字段,包括具有未知或动态名称的文档字段。

db.collection.createIndex( { "$**": 1 } )

重要

对于大型集合,我们建议使用本文档后面定义的替代方法。

包括或排除特定字段

通配符索引也可以限制为特定字段,同时将某些字段排除在索引目标之外。 让我们来看看以下 JSON 示例。

{
    "firstName": "Steve",
    "lastName": "Smith",
    "companyName": "Microsoft",
    "division": "Azure",
    "timeInOrgInYears": 7
}

我们可以控制索引行为,本示例限制了在 firstNamelastNametimeInOrgInYears 字段上创建索引。

db.collection.createIndex( { "$**": 1 },
                           {"wildcardProjection" : {  "firstName": 0
                                                    , "lastName": 0
                                                    , "companyName": 1
                                                    , "division": 1
                                                    , "timeInOrgInYears": 0
                                                   }
                           }
                         )

在 wildcardProjection 文档中,值 0 或 1 指示索引中是包含了 (1) 还是排除了 (0) 字段。

为所有字段编制索引的替代方法

此示例介绍了一个简单的解决方法,可在 Azure Cosmos DB for MongoDB vCore 中正式发布通配符索引之前,在最大程度上减少创建单个索引所需的工作量。

请考虑使用以下 json 文档:

{
    "firstName": "Steve",
    "lastName": "Smith",
    "companyName": "Microsoft",
    "division": "Azure",
    "subDivision": "Data & AI",
    "timeInOrgInYears": 7,
    "roles": [
        {
            "teamName" : "Windows",
            "teamSubName" "Operating Systems",
            "timeInTeamInYears": 3
        },
        {
            "teamName" : "Devices",
            "teamSubName" "Surface",
            "timeInTeamInYears": 2
        },
        {
            "teamName" : "Devices",
            "teamSubName" "Surface",
            "timeInTeamInYears": 2
        }
    ]
}

使用通配符索引时,将在封面下创建以下索引。

  • db.collection.createIndex({"firstName", 1})
  • db.collection.createIndex({"lastName", 1})
  • db.collection.createIndex({"companyName", 1})
  • db.collection.createIndex({"division", 1})
  • db.collection.createIndex({"subDivision", 1})
  • db.collection.createIndex({"timeInOrgInYears", 1})
  • db.collection.createIndex({"subDivision", 1})
  • db.collection.createIndex({"roles.teamName", 1})
  • db.collection.createIndex({"roles.teamSubName", 1})
  • db.collection.createIndex({"roles.timeInTeamInYears", 1})

虽然此示例文档只需要显式索引 10 个字段的组合,但具有数百或数千个字段的大型文档在单独编制字段索引时会非常繁琐且易于出错。

本文档其余部分详述的 jar 文件简化了对较大文档中的字段编制索引的工作。 该 jar 采用示例 JSON 文档作为输入,分析该文档并对每个字段执行 createIndex 命令,而无需用户干预。

先决条件

Java 21

部署虚拟机后,请使用 SSH 连接到计算机,并使用以下命令安装 CQLSH:

# Install default-jdk
sudo apt update
sudo apt install openjdk-21-jdk

为所有字段创建单个索引的示例 jar

克隆包含 Java 示例的存储库,以循环访问 JSON 文档结构中的每个字段,并为文档中每个字段发出 createIndex 操作。

git clone https://github.com/Azure-Samples/cosmosdb-mongodb-vcore-wildcard-indexing.git

如果没有对解决方案进行更改,则无需生成克隆的存储库。 名为 azure-cosmosdb-mongo-data-indexer-1.0-SNAPSHOT.jar 的已生成可运行 jar 已包含在 runnableJar/ 文件夹中。 可以通过指定以下必需的参数来执行 jar:

  • Azure Cosmos DB for MongoDB vCore 群集连接字符串,包含预配群集时使用的用户名与密码
  • Azure Cosmos DB for MongoDB vCore 数据库
  • 要编制索引的集合
  • 包含集合的文档结构的 json 文件的位置。 本文档由 jar 文件分析,以提取每个字段并发出单独的 createIndex 操作。
java -jar azure-cosmosdb-mongo-data-indexer-1.0-SNAPSHOT.jar mongodb+srv://<user>:<password>@abinav-test-benchmarking.global.mongocluster.cosmos.azure.com/?tls=true&authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000 cosmicworks employee sampleEmployee.json

跟踪 createIndex 操作的状态

jar 文件旨在不等待来自每个 createIndex 操作的响应。 索引是在服务器上异步创建的,并且群集上索引生成操作的进度是可以跟踪的。

请考虑此示例,以跟踪“cosmicworks”数据库上编制索引的进度。

use cosmicworks;
db.currentOp()

当正在进行 createIndex 操行时,响应的外观如下所示:

{
  "inprog": [
    {
      "shard": "defaultShard",
      "active": true,
      "type": "op",
      "opid": "30000451493:1719209762286363",
      "op_prefix": 30000451493,
      "currentOpTime": "2024-06-24T06:16:02.000Z",
      "secs_running": 0,
      "command": { "aggregate": "" },
      "op": "command",
      "waitingForLock": false
    },
    {
      "shard": "defaultShard",
      "active": true,
      "type": "op",
      "opid": "30000451876:1719209638351743",
      "op_prefix": 30000451876,
      "currentOpTime": "2024-06-24T06:13:58.000Z",
      "secs_running": 124,
      "command": { "createIndexes": "" },
      "op": "workerCommand",
      "waitingForLock": false,
      "progress": {},
      "msg": ""
    }
  ],
  "ok": 1
}

后续步骤