

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Amazon DocumentDB 中的索引管理搭配 Java
<a name="index-management-java"></a>

索引可讓您從 Amazon DocumentDB 集合有效率地擷取資料。如果沒有索引，DocumentDB 必須掃描集合中的每個文件，以傳回滿足指定查詢的結果。本主題提供如何使用 MongoDB Java 驅動程式建立、捨棄和列出索引的相關資訊。它也會討論如何判斷查詢中是否使用特定索引，以及如何向 Amazon DocumentDB 提供使用特定索引的提示。

**Topics**
+ [建立索引](#creating-indexes)
+ [捨棄索引](#dropping-indes)
+ [決定索引選擇並提供索引提示](#w2aac45b9b7c17c13)

Amazon DocumentDB 支援許多類型的索引。如需所有支援索引的完整概觀，請參閱此[部落格文章](https://aws.amazon.com/blogs/database/how-to-index-on-amazon-documentdb-with-mongodb-compatibility/)。

## 使用 Java 建立索引
<a name="creating-indexes"></a>

使用 MongoDB Java 驅動程式在 Amazon DocumentDB 中建立索引有兩種機制：透過 `runCommand()`，以及透過單一索引`createIndex()`的方法或多個索引`createIndexes()`的方法。使用 `createIndex()`和 `createIndexes()`方法的一個原因是，您可以透過擷取與索引建立相關的特定錯誤來建立更好的錯誤處理。使用這些方法的另一個原因是 MongDB Java `runCommand()` 驅動程式提供一組豐富的支援類別，用於建立和操作索引。請注意，這些支援類別只能在您使用 `createIndex()`或 `createIndexes()`方法時使用。有三種支援類別：
+ **[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html)** — 此類別做為公用程式類別，提供靜態原廠方法來建立各種類型的索引。它簡化了建立複雜索引定義的程序，通常與其他索引相關類別搭配使用。
+ **[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html)** — 這是封裝索引鍵定義及其選項的基本類別。它代表完整的索引規格，結合要編製索引的內容 （索引鍵） 與如何編製索引 （選項）。此類別在同時建立多個索引時特別有用，因為它可讓您定義可傳遞給 `createIndexes()`方法的索引規格集合。
+ **[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html)** — 這是全方位的組態類別，提供一組豐富的方法來自訂索引行為。它包含唯一索引、稀疏索引、過期時間 (TTL) 和部分篩選條件表達式的設定。透過方法鏈結，您可以設定多個選項，例如背景索引建置和唯一限制條件。

**建立單一索引**

此範例示範如何在背景中使用 `createIndex(`) 方法建立單一索引。若要了解背景和前景索引的建立，請參閱 [索引建置類型](managing-indexes.md#index-build-types)。下列程式碼範例使用 在背景中[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexOptions.html)建立名稱為「unique\_restaurantId\_idx」的唯一索引。此`IndexOptions`物件接著會傳遞至 `createIndex()`方法。

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

**建立多個索引**

此範例使用 `createIndexes()`方法建立多個索引。它會先使用 [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html) 物件為每個索引建置 選項，然後將`IndexModel`物件清單傳遞給 `createIndexes()`方法。下列程式碼範例示範如何使用 [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/Indexes.html)公用程式類別建立複合索引。此類別也用於指定您是否要使用遞增或遞減排序順序建立索引。建立多個索引之後，它會呼叫 `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()));
```

**建立稀疏和部分索引**

此範例顯示 [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/client/model/IndexModel.html) 會針對每種索引類型建立 ，以建立稀疏和部分索引。

```
// 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 支援平行索引建立，以減少建立索引所需的時間。平行索引會使用多個並行工作者。用於建立索引的預設工作者為兩個。此[部落格文章](https://aws.amazon.com/blogs/database/unlock-the-power-of-parallel-indexing-in-amazon-documentdb/)提供有關平行索引的深入討論。目前，當您使用 `createIndex()`或 時，MongDB Java 驅動程式不支援指定工作者選項，`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);
```

## 捨棄索引
<a name="dropping-indes"></a>

MongoDB Java 驅動程式提供多種方法來捨棄索引，並滿足不同案例和您的偏好設定。您可以依名稱、金鑰規格或一次捨棄所有索引來捨棄索引。方法 `dropIndex()`和 `dropIndexes()`可以在集合物件上叫用，以捨棄索引。依名稱捨棄索引時，您應該確保索引使用正確的索引名稱，這不一定是直覺式的，尤其是複合或自動產生的索引。嘗試捨棄不存在的索引將導致 [https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoCommandException.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/MongoCommandException.html)。`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}}
```

## 決定索引選擇並提供索引提示
<a name="w2aac45b9b7c17c13"></a>

在 Amazon DocumentDB 中使用解釋功能對您了解查詢效能和索引用量至關重要。執行查詢時，您可以附加 `explain()`方法，以取得查詢計劃的詳細資訊，包括正在使用哪些索引。`explain()` 輸出提供查詢執行階段的深入見解、檢查的文件數量，以及每個階段所花費的時間。此資訊對於識別特定索引是否有效使用，或查詢是否可能受益於不同的索引結構來說非常寶貴。

`explain()` 方法可以使用 `find()`方法鏈結。`explain()` 方法可以採用選用[https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/ExplainVerbosity.html](https://mongodb.github.io/mongo-java-driver/5.3/apidocs/mongodb-driver-core/com/mongodb/ExplainVerbosity.html)列舉，以決定 傳回的詳細程度`explain()`。目前，DocumentDB 僅支援 `QUERY_PLANNER` `EXECUTION_STATS`和 列舉器。下列程式碼範例示範如何取得特定查詢的查詢規劃器：

```
// 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));
```