

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Java による Amazon DocumentDB でのインデックス管理
<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()` メソッドのいずれかによるものの 2 つがあります。`createIndex()` および `createIndexes()` メソッドを使用する理由の 1 つは、インデックス作成に関連する特定のエラーをキャッチすることで、より良いエラー処理を構築できることです。これらのメソッドを `runCommand()` で使用するもう 1 つの理由は、MongDB Java ドライバーがインデックスの作成と操作のための豊富なサポートクラスを提供することです。これらのサポートクラスは、`createIndex()` または `createIndexes()` メソッドを使用している場合にのみ使用できることに注意してください。3 つのサポートクラスがあります。
+ **[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))));
```

**テキストインデックスを作成する**

この例では、テキストインデックスを作成する方法を示します。コレクションでは 1 つのテキストインデックスのみが許可されますが、1 つのテキストインデックスを複数のフィールドをカバーする複合インデックスにすることができます。テキストインデックスで複数のフィールドを使用する場合、インデックス内の各フィールドに重みを割り当てることもできます。配列フィールドのテキストインデックスは Amazon DocumentDB ではサポートされていません。複合テキストインデックスでは最大 30 個のフィールドを使用できますが、重みを割り当てることができるフィールドは 3 つだけです。

```
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 は、インデックスの作成にかかる時間を短縮するための並列インデックス作成をサポートしています。並列インデックス作成は、複数の同時ワーカーを使用します。インデックスの作成に使用されるデフォルトのワーカーは 2 つです。この [ブログ記事](https://aws.amazon.com/blogs/database/unlock-the-power-of-parallel-indexing-in-amazon-documentdb/) では、並列インデックス作成について詳しく説明します。現在、MongDB Java ドライバーは、`createIndex()` または `createIndexes()` を使用しているときにワーカーオプションの指定をサポートしていないため、ワーカーを指定する唯一の方法は `runCommand` を使用することです。次のコード例は、`runCommand` を使用して、ワーカーを 4 つに増やすインデックスを作成する方法を示しています。

```
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()` メソッドは、`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) 列挙値を取ることができます。現時点では、`EXECUTION_STATS` および `QUERY_PLANNER` 列挙子のみが DocumentDB でサポートされています。次のコード例は、特定のクエリのクエリプランナーを取得する方法を示しています。

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