使用 Java 在亚马逊文档数据库中管理索引 - Amazon DocumentDB

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用 Java 在亚马逊文档数据库中管理索引

索引允许从 Amazon DocumentDB 集合中高效检索数据。如果没有索引,DocumentDB 必须扫描集合中的每个文档才能返回满足给定查询的结果。本主题提供有关如何使用 MongoDB Java 驱动程序创建、删除和列出索引的信息。它还讨论了如何确定查询中是否使用了特定的索引,以及如何向 Amazon DocumentDB 提供使用特定索引的提示。

亚马逊 DocumentDB 支持多种类型的索引。有关所有支持的索引的全面概述,请参阅此博客文章

使用 Java 创建索引

使用 MongoDB Java 驱动程序在 Amazon DocumentDB 中创建索引有两种机制:通过runCommand(),以及通过创建单个索引的createIndex()方法或创建多个索引的方法。createIndexes()使用createIndex()createIndexes()方法的原因之一是,通过捕获与创建索引相关的特定错误,您可以更好地处理错误。使用这些方法的另一个原因runCommand()是 MongDB Java 驱动程序为索引创建和操作提供了一组丰富的支持类。请注意,这些支持类只能在使用createIndex()createIndexes()方法时使用。有三个辅助课程:

  • Indexes— 该类用作实用程序类,提供用于创建各种类型索引的静态工厂方法。它简化了创建复杂索引定义的过程,通常与其他与索引相关的类一起使用。

  • IndexModel— 这是一个封装索引键定义及其选项的基础类。它代表了一个完整的索引规范,将索引内容(键)与如何索引(选项)结合在一起。该类在同时创建多个索引时特别有用,因为它允许您定义一组可以传递给该createIndexes()方法的索引规范。

  • IndexOptions— 这是一个全面的配置类,它为自定义索引行为提供了一组丰富的方法。它包括唯一索引、稀疏索引、过期时间 (TTL) 和部分筛选表达式的设置。通过方法链接,您可以配置多个选项,例如后台索引构建和唯一约束。

创建单个索引

此示例说明如何在后台使用createIndex() 方法创建单个索引。要了解背景和前台索引的创建,请参阅。索引构建类型以下代码示例用于IndexOptions在后台创建名为 “unique_restaurantid_idx” 的唯一索引。然后IndexOptions将此对象传递给该createIndex()方法。

collection.createIndex( Indexes.ascending("restaurantId"), new IndexOptions() .unique(true) .name("unique_restaurantId_idx") .background(true));

创建多个索引

此示例使用createIndexes()方法创建多个索引。它首先使用对象为每个索引构建选项,然后将IndexModel对象列表传递给该createIndexes()方法。IndexModel以下代码示例说明如何使用Indexes实用程序类创建复合索引。该类还用于指定是要使用升序还是降序排序顺序创建索引。创建多个索引后,它会通过调用listIndexes()方法来验证索引的创建。

// Single Field Index on cuisine IndexModel singleIndex = new IndexModel( Indexes.ascending("cuisine"), new IndexOptions().name("cuisine_idx")); // Compound Index IndexModel compoundIndex = new IndexModel( Indexes.compoundIndex( Indexes.ascending("address.state"), Indexes.ascending("priceRange")), new IndexOptions().name("location_price_idx")); // Build a list of IndexModel for the indexes List < IndexModel > indexes = Arrays.asList( singleIndex, compoundIndex ); collection.createIndexes(indexes); // Verify created indexes collection.listIndexes().forEach(index - > System.out.println("Created index: " + index.toJson()));

创建稀疏索引和部分索引

此示例显示通过为每种类型的索引创建稀疏索引IndexModel和部分索引。

// Sparse Index Model, this will identify only those documents that have a // michelin star rating IndexModel sparseIndex = new IndexModel( Indexes.ascending("michelin.star"), new IndexOptions() .name("michelin_sparse_idx") .sparse(true)); // Partial Index Model where the restaurant is active and has a rating of 4 and above IndexModel partialIndex = new IndexModel( Indexes.ascending("rating.average"), new IndexOptions() .name("high_rated_active_idx") .partialFilterExpression( Filters.and( Filters.eq("isActive", true), Filters.gte("rating.average", 4.0))));

创建文本索引

此示例说明如何创建文本索引。一个集合上只允许有一个文本索引,但该文本索引可以是覆盖多个字段的复合索引。在文本索引中使用多个字段时,也可以为索引中的每个字段分配权重。Amazon DocumentDB 不支持数组字段的文本索引,尽管复合文本索引中最多可以使用 30 个字段,但只能为三个字段分配权重。

IndexModel textIndex = new IndexModel( new Document() .append("name", "text") .append("description", "text") .append("cuisine", "text"), new IndexOptions() .name("restaurant_text_idx") .weights(new Document() .append("name", 10) // Restaurant name gets highest weight .append("description", 5) // Description get medium weight .append("cuisine", 2) // Cuisine type gets low weight )); collection.createIndex(textIndex.getKeys(), textIndex.getOptions());

使用创建索引 runCommand()

Amazon DocumentDB 支持并行索引创建,以缩短创建索引所需的时间。并行索引使用多个并发工作程序。用于创建索引的默认工作线程是两个。这篇博文对并行索引进行了深入讨论。当前,MongDB Java 驱动程序不支持在使用createIndex()或时指定工作器选项createIndexes(),因此指定工作程序的唯一方法是通过。runCommand以下代码示例演示了runCommand如何使用创建将工作器增加到四的索引:

Document command = new Document("createIndexes", "Restaurants") .append("indexes", Arrays.asList( new Document("key", new Document("name", 1)) .append("name", "restaurant_name_idx") .append("workers", 4) // Specify number of workers )); Document commendResult = connectedDB.runCommand(command);

删除索引

MongoDB Java 驱动程序提供了多种删除索引的方法,可满足不同的场景和您的偏好。您可以按名称、按键规格删除索引,也可以一次删除所有索引。dropIndexes()可以在集合对象上调用方法dropIndex()和来删除索引。按名称删除索引时,应确保它们使用正确的索引名称,这可能并不总是直观的,特别是对于复合索引或自动生成的索引。尝试删除不存在的索引将导致. MongoCommandException 不能删除default _id索引,因为它可以确保集合中文档的唯一性。

以下代码示例演示如何通过提供创建索引的字段名或删除所有索引来删除索引:

String indexName = "unique_restaurantId_idx"; Document keys = new Document("cuisine", 1); // Drop index by name collection.dropIndex(indexName); // Drop index by keys collection.dropIndex(keys); // Drop all indexes collection.dropIndexes();

使用多个键删除索引时,请确保有一个包含所有指定键的复合索引,并且键的顺序正确。上面的索引创建示例代码显示了 “cuisine” 和功能的复合键。如果您尝试删除该复合键,但顺序不是创建时使用的顺序,则会出现如下 MongoCommnadException 错误:

Document keys = new Document("features", 1) .append("cuisine", 1); try { // Drop index by keys collection.dropIndex(keys); System.out.println("Successfully dropped index with keys: " + keys.toJson()); } catch (MongoCommandException commErr) { System.out.println("Error dropping index: " + commErr.getErrorMessage()); throw new RuntimeException("MongoCommandException was thrown while dropping index", commErr); }

将显示以下错误:

Error dropping index: Cannot drop index: index not found. Tests run: 3, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.819 sec <<< FAILURE! com.amazon.docdb.guide.DocDBGuideTest.testindexGuide() Time elapsed: 0.817 sec <<< FAILURE! org.opentest4j.AssertionFailedError: Unexpected exception thrown: java.lang.RuntimeException: MongoCommandException was thrown while dropping index

确定索引选择并提供索引提示

使用 Amazon DocumentDB 中的解释功能对于了解查询性能和索引使用情况至关重要。执行查询时,您可以附加explain()方法以获取有关查询计划的详细信息,包括正在使用哪些索引(如果有)。explain()输出提供了对查询执行阶段、检查的文档数量以及每个阶段所花费时间的见解。这些信息对于确定特定索引是否得到有效使用或查询是否可以从不同的索引结构中受益非常有用。

explain()方法可以与该find()方法链接。该explain()方法可以采用一个可选的ExplainVerbosity枚举来确定返回的详细程度。explain()目前,DocumentDB 仅支持EXECUTION_STATSQUERY_PLANNER枚举器。以下代码示例显示了如何获取特定查询的查询计划器:

// Query we want to analyze Document query = new Document() .append("cuisine", "Thai") .append("rating.average", new Document("$gte", 4.0)); Document allPlansExplain = collection.find(query).explain(ExplainVerbosity.QUERY_PLANNER); System.out.println("All Plans Explain:\n" + allPlansExplain.toJson());

查询计划器详细级别将返回以下 JSON 文档:

{ "queryPlanner": { "plannerVersion": 1, "namespace": "ProgGuideData.Restaurants", "winningPlan": { "stage": "IXSCAN", "indexName": "cuisine_idx", "direction": "forward" } }, "serverInfo": { "host": "guidecluster3", "port": 27017, "version": "5.0.0" }, "ok": 1, "operationTime": { "$timestamp": { "t": 1739221668, "i": 1 } } }

您可以通过多种方式来影响或强制 Amazon DocumentDB 使用特定索引。hint()hintString()方法允许您通过明确指定查询应使用哪个索引来覆盖查询优化器的默认索引选择行为。虽然 DocumentDB 的查询优化器通常会为索引选择做出不错的选择,但在某些情况下,强制使用特定索引hint()hintString()可能有益,例如在处理倾斜的数据或测试索引性能时。

以下代码示例强制使用复合索引 “cuisine_features_idx” 来处理在上述代码中运行的相同查询:

// Query we want to analyze Document query = new Document() .append("cuisine", "Thai") .append("rating.average", new Document("$gte", 4.0)); List < Document > queryDocs = new ArrayList < > (); collection.find(query).hintString("cuisine_features_idx").forEach(doc - > queryDocs.add(doc));