Overview
このガイドでは、MongoDB Java ドライバーでインデックスを使用する方法を学習できます。
インデックスは、MongoDB でクエリを効率的に実行するのに役立ちます。 インデックスがないと、MongoDB はコレクション内のすべてのドキュメントをスキャンする必要があります(コレクションスキャン)。 これらのコレクションスキャンは遅く、アプリケーションのパフォーマンスに悪影響を与える可能性があります。 クエリに適切なインデックスがある場合、MongoDB ではそのインデックスを使用して検査する必要があるドキュメントを制限できます。
インデックスも:
Tip
インデックスは、アップデートするドキュメントを見つけるときはアップデート操作、削除するドキュメントを見つけた場合は削除操作、および 集計パイプライン の特定のステージでも使用されます。
クエリ範囲とパフォーマンス
MongoDB に対してクエリを実行する場合、 コマンドにはさまざまな要素を含めることができます。
検索するフィールドと値を指定するクエリ条件
読み取り保証など、クエリの実行に影響するオプション
MongoDB が返すフィールドを指定するためのプロジェクション基準(任意)
MongoDB から返されるドキュメントの順序を指定するためのソート基準(任意)
クエリ、プロジェクション、ソートで指定されたすべてのフィールドが同じインデックスにある場合、MongoDB はインデックスから直接結果を返します。これはカバード クエリとも呼ばれます。
重要
並び替え順
ソート条件は、インデックスの順序と一致するか、その順序を逆にする必要があります。
name昇順(AZ)でフィールドage と降順(9-0)のフィールド のインデックスを検討します。
name_1_age_-1
MongoDB は、データを次のいずれかでソートするときにこのインデックスを使用します。
name昇順、age降順name降順、ageの昇順
nameと ageの昇順、またはnameとageの降順の並べ替え順序を指定するには、メモリ内でソートする必要があります。
インデックスがクエリ条件とプロジェクションをカバーするようにする方法について詳しくは、MongoDB マニュアルのクエリ カバレッジ に関する記事を参照してください。
操作上の考慮事項
クエリのパフォーマンスを向上させるには、ソートされた結果を返すアプリケーションのクエリや操作で頻繁に表示されるフィールドにインデックスをビルドします。 追加する各インデックスはアクティブな場合にディスク領域とメモリを消費するため、キャパシティー プランニングとしてインデックス メモリとディスク使用量を追跡することをお勧めします。 さらに、書込み操作によってインデックス付きフィールドがアップデートされると、MongoDB は関連するインデックスをアップデートします。
MongoDB は動的スキーマをサポートしているため、アプリケーションは名前が事前に不明または任意のフィールドに対してクエリを実行できます。ワイルドカード インデックスはこれらのクエリをサポートするのに役立ちますが、ワークロードベースのインデックスプランニングを置き換えるように設計されていません。
データモデルの設計とアプリケーションに適したインデックスの選択の詳細については、「 MongoDB Server のデータ モデリングとインデックス 」を参照してください。
インデックス タイプ
MongoDB は、データのクエリをサポートするためにさまざまなインデックス タイプをサポートしています。 以下のセクションでは、最も一般的なインデックス型について説明し、各インデックス型を作成するためのサンプルコードを示します。 インデックス タイプの完全なリストについては、「インデックス 」を参照してください。
Tip
MongoDB Javaドライバーは、さまざまなMongoDBインデックス キー タイプのインデックス仕様ドキュメントを作成するための静的ファクトリー メソッドを含む Indexes クラスを提供します。
次の例では、createIndex() メソッドを使用してさまざまなインデックスと次の設定を作成します。
import com.mongodb.DuplicateKeyException; import com.mongodb.MongoCommandException; import com.mongodb.client.*; import com.mongodb.client.model.IndexOptions; import com.mongodb.client.model.Indexes; import com.mongodb.client.model.Sorts; import com.mongodb.client.model.geojson.Point; import com.mongodb.client.model.geojson.Position; import org.apache.log4j.BasicConfigurator; import org.bson.Document; import org.bson.conversions.Bson; import static com.mongodb.client.model.Filters.*; import static com.mongodb.client.model.Projections.*;
final String uri = "mongodb+srv://<atlas-uri>/<dbname>?retryWrites=true&w=majority"; mongoClient = MongoClients.create(uri); database = mongoClient.getDatabase("sample_mflix"); collection = database.getCollection("movies");
単一フィールドと複合インデックス
単一フィールド インデックス
単一フィールド インデックスは、コレクションのドキュメント内の単一のフィールドを参照するインデックスです。 単一フィールド クエリとソートのパフォーマンスが向上し、一定時間の経過後または特定のクロック時間にコレクションからドキュメントを自動的に排除するTTL インデックスをサポートします。
注意
_id_インデックスは、単一フィールド インデックスの例です。 このインデックスは、新しいコレクションが作成されるときに、 _idフィールドに自動的に作成されます。
次の例では、 titleフィールドに昇順のインデックスを作成します。
String resultCreateIndex = collection.createIndex(Indexes.ascending("title")); System.out.println(String.format("Index created: %s", resultCreateIndex));
以下は、前のコード スニペットで作成されたインデックスによってカバーされるクエリの例です。
Bson filter = eq("title", "Batman"); Bson sort = Sorts.ascending("title"); Bson projection = fields(include("title"), excludeId()); FindIterable<Document> cursor = collection.find(filter).sort(sort).projection(projection);
複合インデックス
複合インデックス は、コレクションのドキュメント内の複数のフィールドへの参照を保持し、クエリとソートのパフォーマンスを向上させます。
Tip
複合インデックス、インデックス プレフィックス、ソート順序の詳細については、こちらをご覧ください。
次の例では、 フィールドと フィールドに複合インデックスを作成しています。typerated
String resultCreateIndex = collection.createIndex(Indexes.ascending("type", "rated")); System.out.println(String.format("Index created: %s", resultCreateIndex));
以下は、前のコード スニペットで作成されたインデックスによってカバーされるクエリの例です。
Bson filter = and(eq("type", "movie"), eq("rated", "G")); Bson sort = Sorts.ascending("type", "rated"); Bson projection = fields(include("type", "rated"), excludeId()); FindIterable<Document> cursor = collection.find(filter).sort(sort).projection(projection);
詳細については、 マニュアルの「 複合インデックス MongoDB Server」を参照してください。
マルチキー インデックス(配列フィールドへのインデックス)
マルチキー インデックスは、配列値を含むインデックスを持つフィールドを指定するクエリのパフォーマンスを向上させるインデックスです。 単一フィールドまたは複合インデックスと同じ構文を使用してマルチキー インデックスを定義できます。
次の例では、 rated 、 genres (文字列の配列)、 titleフィールドに複合マルチキー インデックスを作成します。
String resultCreateIndex = collection.createIndex(Indexes.ascending("rated", "genres", "title")); System.out.println(String.format("Index created: %s", resultCreateIndex));
以下は、前のコード スニペットで作成されたインデックスによってカバーされるクエリの例です。
Bson filter = and(eq("genres", "Animation"), eq("rated", "G")); Bson sort = Sorts.ascending("title"); Bson projection = fields(include("title", "rated"), excludeId()); FindIterable<Document> cursor = collection.find(filter).sort(sort).projection(projection);
マルチキー インデックスは、クエリ カバレッジ、インデックスバウンド計算、およびソート動作の点で他のインデックスとは動作が異なります。 マルチキー インデックス(動作や制限事項を含む)の詳細については、MongoDB マニュアルの「 マルチキー インデックス 」のページを参照してください。
Atlas Search インデックス
Atlas Search 機能を使用すると、MongoDB Atlas でホストされているコレクションに対して全文検索を実行できます。 インデックスは、検索の動作とインデックスを作成するフィールドを指定します。
MongoDB Atlas Search の詳細については、「 Atlas Search インデックス」のドキュメントを参照してください。
コレクションに対して次のメソッドを呼び出して、Atlas Search インデックスを管理できます。
createSearchIndex()createSearchIndexes()listSearchIndexes()updateSearchIndex()dropSearchIndex()
注意
Atlas Search インデックス マネジメントのメソッドは非同期で実行されます。ドライバー メソッドは、正常に実行されたことを確認する前に戻ることができます。インデックスの現在のステータスを確認するには、listSearchIndexes() メソッドを呼び出します。
次のセクションでは、前述の各メソッドの使用方法を示すコード例を示します。
検索インデックスを作成
Atlas Search インデックスを作成するには、 createSearchIndex() メソッドと createSearchIndexes() メソッドを使用できます。
次のコード例は、単一インデックスを作成する方法を示しています。
Document index = new Document("mappings", new Document("dynamic", true)); collection.createSearchIndex("myIndex", index);
次のコード例は、複数のインデックスを作成する方法を示しています。
SearchIndexModel indexOne = new SearchIndexModel("myIndex1", new Document("analyzer", "lucene.standard").append( "mappings", new Document("dynamic", true))); SearchIndexModel indexTwo = new SearchIndexModel("myIndex2", new Document("analyzer", "lucene.simple").append( "mappings", new Document("dynamic", true))); collection.createSearchIndexes(Arrays.asList(indexOne, indexTwo));
検索インデックスをリストする
listSearchIndexes() メソッドを使用して、コレクションの Atlas Search インデックスを返すことができます。
次のコード例は、コレクションの検索インデックスのリストを出力する方法を示しています。
try (MongoCursor<Document> resultsCursor = collection.listSearchIndexes().iterator()) { while (resultsCursor.hasNext()) { System.out.println(resultsCursor.next()); } }
検索インデックスをアップデートする
updateSearchIndex() メソッドを使用して、Atlas Searchインデックスを更新できます。
次のコードは、検索インデックスを更新する方法を示しています。
collection.updateSearchIndex("myIndex", new Document("analyzer", "lucene.simple").append( "mappings", new Document("dynamic", false) .append("fields", new Document("title", new Document("type", "string"))) ) );
検索インデックスを削除する
dropSearchIndex() メソッドを使用して、Atlas Searchインデックスを削除することができます。
次のコードは、コレクションから検索インデックスを削除する方法を示しています。
collection.dropSearchIndex("myIndex");
Text Indexes
テキスト インデックスは、string コンテンツに対するテキスト検索クエリをサポートします。 これらのインデックスには、値が string または複数の string 配列である任意のフィールドを含めることができます。 MongoDB はさまざまな言語のテキスト検索をサポートしています。 インデックスの作成時に、オプションとしてデフォルト言語を指定できます。
Tip
MongoDB は、改良された全文検索ソリューションであるAtlas Searchを提供します。 Atlas Search インデックスとその使用方法の詳細については、このガイドの「 Atlas Search インデックス」セクションを参照してください。
シングル フィールド
次の例では、 plotフィールドに テキスト インデックスを作成しています。
try { String resultCreateIndex = collection.createIndex(Indexes.text("plot")); System.out.println(String.format("Index created: %s", resultCreateIndex)); // Prints a message if a text index already exists with a different configuration } catch (MongoCommandException e) { if (e.getErrorCodeName().equals("IndexOptionsConflict")) System.out.println("there's an existing text index with different options"); }
以下は、前のコード スニペットで作成されたインデックスを使用するクエリの例です。 テキスト インデックスにはソート順序が含まれていないため、 sortは省略されていることに注意してください。
Bson filter = text("java coffee shop"); Bson projection = fields(include("fullplot"), excludeId()); FindIterable<Document> cursor = collection.find(filter).projection(projection);
複数のフィールド
コレクションには 1 つのテキスト インデックスしか含めることができません。 複数のテキストフィールドのテキストインデックスを作成する場合は、複合インデックスを作成する必要があります。 複合インデックス内のすべてのテキスト フィールドに対してテキスト検索が実行されます。
次のスニペットは、 フィールドと フィールドの複合テキストtitle genreインデックスを作成します。
collection.createIndex(Indexes.compoundIndex(Indexes.text("title"), Indexes.text("genre")));
詳細については、次のサーバー マニュアル エントリを参照してください。
地理空間インデックス
MongoDB は、 2 dsphere インデックスを使用した地理空間座標データのクエリをサポートしています。 2dsphereインデックスを使用すると、包含、交差、近接性について地理空間データを照会できます。 地理空間データのクエリの詳細については、「地理空間クエリ 」を参照してください。
2dsphereインデックスを作成するには、 GeoJSON オブジェクトのみを含むフィールドを指定する必要があります。 これについて詳しくは、MongoDB Server マニュアルの「 GeoJSON オブジェクト 」のページを参照してください。
sample_mflixデータベース内のtheatersコレクションの次のサンプル ドキュメントのlocation.geoフィールドは、劇場の座標を記述する GeoJSON ポイント オブジェクトです。
{ "_id" : ObjectId("59a47286cfa9a3a73e51e75c"), "theaterId" : 104, "location" : { "address" : { "street1" : "5000 W 147th St", "city" : "Hawthorne", "state" : "CA", "zipcode" : "90250" }, "geo" : { "type" : "Point", "coordinates" : [ -118.36559, 33.897167 ] } } }
次の例では、 location.geoフィールドに2dsphereインデックスを作成します。
重要
地理空間インデックスによってカバーされているフィールドに地理空間インデックスを作成しようとすると、エラーが発生します。
try { String resultCreateIndex = collection.createIndex(Indexes.geo2dsphere("location.geo")); System.out.println(String.format("Index created: %s", resultCreateIndex)); // Prints a message if a geospatial index already exists with a different configuration } catch (MongoCommandException e) { if (e.getErrorCodeName().equals("IndexOptionsConflict")) System.out.println("there's an existing geospatial index with different options"); }
以下は、「location.geo」を使用した地理空間クエリの例です。 インデックス。
// Stores the coordinates of the NY MongoDB headquarters Point refPoint = new Point(new Position(-73.98456, 40.7612)); // Retrieves documents that represent locations up to 1000 meters from the specified point directly from the geospatial index // Creates a filter to match a document Bson filter = near("location.geo", refPoint, 1000.0, 0.0); FindIterable<Document> cursor = collection.find(filter);
MongoDB は、ユークリッド平面上の距離を計算し、MongoDB 2.2以前で使用される「legacy coordinate pairs」構文を操作するための2dインデックスもサポートしています。 詳細については、MongoDB Server マニュアルの「 地理空間クエリ 」ページ を参照してください。
Unique Indexes
ユニークインデックスにより、インデックス フィールドに重複する値が格納されなくなります。デフォルトでは、MongoDB はコレクションの作成時に _id フィールドにユニークインデックスを作成します。ユニークインデックスを作成するには、重複を防ぐフィールドまたはフィールドの組み合わせを指定し、unique オプションを true に設定します。
次の例では、 theaterIdフィールドに一意の降順インデックスを作成しています。
try { IndexOptions indexOptions = new IndexOptions().unique(true); String resultCreateIndex = collection.createIndex(Indexes.descending("theaterId"), indexOptions); System.out.println(String.format("Index created: %s", resultCreateIndex)); // Prints a message if the "theaterID" field contains duplicate values } catch (DuplicateKeyException e) { System.out.printf("duplicate field values encountered, couldn't create index: \t%s\n", e); }
重要
一意なインデックスに違反する重複値を保存する書込み操作を実行すると、MongoDB Java ドライバーはDuplicateKeyExceptionを発生させ、MongoDB は次のようなエラーを返します。
E11000 duplicate key error index
ワイルドカード インデックス
ワイルドカード インデックスを使用すると、不明なフィールドや任意のフィールドに対するクエリが可能になります。 動的スキーマを使用している場合は、これらのインデックスが役立ちます。
次の例では、サブドキュメントや配列にネストされた値を含む、 locationフィールドのすべての値に対して昇順のワイルドカード インデックスを作成します。
String resultCreateIndex = collection.createIndex(Indexes.ascending("location.$**")); System.out.println(String.format("Index created: %s", resultCreateIndex));
詳細については、MongoDB Server マニュアルの「 ワイルドカード インデックス 」のページを参照してください。
クラスター化インデックス
クラスター化されたインデックスは、キー値の順にドキュメントを保存するようにコレクションに指示します。 クラスター化インデックスを作成するには、コレクションを作成するときに、 _idフィールドをキーとして指定し、一意のフィールドをtrueとして指定して、 クラスター化インデックス オプション を指定します。
次の例では、 vendorsコレクションの_idフィールドにクラスター化インデックスを作成しています。
MongoDatabase database = mongoClient.getDatabase("tea"); ClusteredIndexOptions clusteredIndexOptions = new ClusteredIndexOptions(new Document("_id", 1), true); CreateCollectionOptions createCollectionOptions = new CreateCollectionOptions().clusteredIndexOptions(clusteredIndexOptions); database.createCollection("vendors", createCollectionOptions);
詳細については、MongoDB Server マニュアルの各セクションを参照してください。
インデックスを削除する
_idフィールドのデフォルトの一意なインデックスを除く未使用のインデックスを削除できます。
次のセクションでは、インデックスを削除する方法を示します。
インデックス仕様ドキュメントの使用
インデックス付き名前フィールドの使用
ワイルドカード文字を使用してすべてのインデックスを削除する
インデックス仕様ドキュメントを使用したインデックスの削除
インデックス仕様ドキュメントをdropIndex()メソッドに渡して、コレクションからインデックスを削除します。 インデックス仕様ドキュメントは、指定されたフィールドのインデックスのタイプを指定するBsonインスタンスです。
次のスニペットは、 コレクションのtitleフィールドの昇順のインデックスを削除します。
collection.dropIndex(Indexes.ascending("title"));
重要
テキスト インデックスを削除する場合は、代わりにインデックスの名前を使用する必要があります。 詳細については、「 名前フィールドを使用したインデックスの削除 」セクションを参照してください。
名前フィールドを使用したインデックスの削除
コレクションからインデックスを削除するには、インデックスのnameフィールドをdropIndex()メソッドに渡します。
インデックスの名前を見つけるには、 listIndexes()メソッドを使用して、インデックス内のnameフィールドの値を確認します。
次のスニペットは、コレクション内のすべてのインデックスを検索して出力します。
collection.listIndexes().forEach(doc -> System.out.println(doc.toJson()));
テキスト インデックスを含むコレクションでlistIndex()を呼び出すと、出力は次のようになります。
{ "v": 2, "key": {"_id": 1}, "name": "_id_" } { "v": 2, "key": {"_fts": "text", "_ftsx": 1}, "name": "title_text", "weights": {"title": 1}, "default_language": "english", "language_override": "language", "textIndexVersion": 3 }
この出力では、既存のインデックスの名前が "_id" と "title_text" であることがわかります。
次のスニペットは、 コレクションから "title_text" インデックスを削除します。
collection.dropIndex("title_text");
注意
複合テキスト インデックスから単一のフィールドを削除することはできません。 インデックス フィールドを更新するには、インデックス全体を削除し、新しいインデックスを作成する必要があります。
ワイルドカード文字を使用したインデックスの削除
MongoDB 4.2 以降では、コレクションでdropIndexes()メソッドを呼び出すことで、すべてのインデックスを削除できます。
collection.dropIndexes();
以前のバージョンの MongoDB の場合は、コレクションのdropIndex()への呼び出しに「*」をパラメータとして渡します。
collection.dropIndex("*");
このセクションのメソッドの詳細については、次の API ドキュメントを参照してください。