Overview
このガイドでは、MongoDB Kotlin ドライバーを使用してインデックスを作成および管理する方法を学習できます。
インデックスは、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 は、データのクエリをサポートするためにさまざまなインデックス タイプをサポートしています。 以下のセクションでは、最も一般的なインデックス型について説明し、各インデックス型を作成するためのサンプルコードを示します。 インデックス タイプの完全なリストについては、サーバー マニュアルの「インデックス」を参照してください。
Tip
Kotlinドライバーは、インデックスを作成および管理するための Indexes クラスを提供します。このクラスには、さまざまなMongoDBインデックスキー タイプのインデックス仕様ドキュメントを作成するための静的ファクトリー メソッドが含まれています。
次の例では、createIndex() メソッドを使用してさまざまなインデックスを作成し、次のデータ クラスを使用してMongoDBのデータをモデル化します。
// Data class for the movies collection data class Movie( val title: String, val year: Int, val cast: List<String>, val genres: List<String>, val type: String, val rated: String, val plot: String, val fullplot: String, ) // Data class for the theaters collection data class Theater( val theaterId: Int, val location: Location ) { data class Location( val address: Address, val geo: Point ) { data class Address( val street1: String, val city: String, val state: String, val zipcode: String ) } }
単一フィールドと複合インデックス
単一フィールド インデックス
単一フィールド インデックスは、コレクションのドキュメント内の単一のフィールドを参照するインデックスです。 単一フィールド クエリとソートのパフォーマンスが向上し、一定時間の経過後または特定のクロック時間にコレクションからドキュメントを自動的に排除するTTL インデックスをサポートします。
注意
_id_インデックスは、単一フィールド インデックスの例です。 このインデックスは、新しいコレクションが作成されるときに、 _idフィールドに自動的に作成されます。
次の例では、 titleフィールドに昇順のインデックスを作成します。
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::title.name)) println("Index created: $resultCreateIndex")
Index created: title_1
以下は、前のコード スニペットで作成されたインデックスによってカバーされるクエリの例です。
val filter = Filters.eq(Movie::title.name, "The Dark Knight") val sort = Sorts.ascending(Movie::title.name) val projection = Projections.fields( Projections.include(Movie::title.name), Projections.excludeId() ) data class Results(val title: String) val resultsFlow = moviesCollection.find<Results>(filter).sort(sort).projection(projection) resultsFlow.collect { println(it) }
詳細については、 MongoDB サーバー マニュアルの単一フィールド インデックスのセクションを参照してください。
複合インデックス
複合インデックス は、コレクションのドキュメント内の複数のフィールドへの参照を保持し、クエリとソートのパフォーマンスを向上させます。
Tip
複合インデックス、インデックス プレフィックス、ソート順序の詳細については、こちらをご覧ください。
次の例では、 フィールドと フィールドに複合インデックスを作成しています。typerated
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::type.name, Movie::rated.name)) println("Index created: $resultCreateIndex")
Index created: type_1_rated_1
以下は、前のコード スニペットで作成されたインデックスによってカバーされるクエリの例です。
val filter = Filters.and( Filters.eq(Movie::type.name, "movie"), Filters.eq(Movie::rated.name, "G") ) val sort = Sorts.ascending(Movie::type.name, Movie::rated.name) val projection = Projections.fields( Projections.include(Movie::type.name, Movie::rated.name), Projections.excludeId() ) val resultsFlow = moviesCollection.find(filter).sort(sort).projection(projection) resultsFlow.collect { println(it) }
詳細については、MongoDB サーバーのマニュアルの「複合インデックス」のセクションを参照してください。
マルチキー インデックス(配列フィールドへのインデックス)
マルチキー インデックスは、配列値を含むインデックスを持つフィールドを指定するクエリのパフォーマンスを向上させるインデックスです。 単一フィールドまたは複合インデックスと同じ構文を使用してマルチキー インデックスを定義できます。
次の例では、 rated 、 genres (文字列の配列)、 titleフィールドに複合マルチキー インデックスを作成します。
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::rated.name, Movie::genres.name, Movie::title.name)) println("Index created: $resultCreateIndex")
Index created: rated_1_genres_1_title_1
以下は、前のコード スニペットで作成されたインデックスによってカバーされるクエリの例です。
val filter = Filters.and( Filters.eq(Movie::genres.name, "Animation"), Filters.eq(Movie::rated.name, "G") ) val sort = Sorts.ascending(Movie::title.name) val projection = Projections.fields( Projections.include(Movie::title.name, Movie::rated.name), Projections.excludeId() ) val resultsFlow = moviesCollection.find(filter).sort(sort).projection(projection) resultsFlow.collect { println(it) }
マルチキー インデックスは、クエリ カバレッジ、インデックスバウンド計算、およびソート動作の点で他のインデックスとは動作が異なります。 マルチキー インデックス(動作や制限事項を含む)の詳細については、サーバー マニュアルの「 マルチキーインデックス」を参照してください。
Atlas Search インデックス
Atlas Search 機能を使用すると、MongoDB Atlas でホストされているコレクションに対して全文検索を実行できます。 インデックスは、特定のフィールドに対する全文検索の実行方法を指定します。
MongoDB Atlas Search の詳細については、「 Atlas Search インデックス」のドキュメントを参照してください。
コレクションに対して次のメソッドを呼び出して、Atlas Search インデックスを管理できます。
createSearchIndex()createSearchIndexes()listSearchIndexes()updateSearchIndex()dropSearchIndex()
注意
Atlas Search インデックス マネジメントのメソッドは非同期で実行されます。 ドライバー メソッドは、正常に実行されたことを確認する前に戻ることができます。 インデックスの現在のステータスを確認するには、 listSearchIndexes()メソッドを呼び出します。
次のセクションでは、前述の各メソッドの使用方法を示すコード例を示します。
検索インデックスを作成
createSearchIndex() メソッドと createSearchIndexes() メソッドを使用して、コレクションに Atlas Search インデックスを作成できます。
次のコード例は、単一インデックスを作成する方法を示しています。
val index = Document( "mappings", Document("dynamic", true) ) val resultCreateIndex = moviesCollection.createSearchIndex("myIndex", index)
次のコード例は、複数のインデックスを作成する方法を示しています。
val indexOne = SearchIndexModel( "myIndex1", Document("analyzer", "lucene.standard").append( "mappings", Document("dynamic", true) ) ) val indexTwo = SearchIndexModel( "myIndex2", Document("analyzer", "lucene.simple").append( "mappings", Document("dynamic", true) ) ) val resultCreateIndexes = moviesCollection .createSearchIndexes(listOf(indexOne, indexTwo))
検索インデックスをリストする
listSearchIndexes() メソッドを使用して、コレクションの Atlas Search インデックスのリストを返すことができます。
次のコード例は、コレクションの検索インデックスのリストを出力する方法を示しています。
val searchIndexesList = moviesCollection.listSearchIndexes().toList()
検索インデックスをアップデートする
updateSearchIndex() メソッドを使用して、Atlas Searchインデックスを更新できます。
次のコードは、検索インデックスを更新する方法を示しています。
moviesCollection.updateSearchIndex( "myIndex", Document("analyzer", "lucene.simple").append( "mappings", Document("dynamic", false) .append( "fields", Document( "title", Document("type", "string") ) ) ) )
検索インデックスを削除する
dropSearchIndex() メソッドを使用して、Atlas Searchインデックスを削除することができます。
次のコードは、コレクションから検索インデックスを削除する方法を示しています。
moviesCollection.dropSearchIndex("myIndex");
Text Indexes
テキスト インデックスは、string コンテンツに対するテキスト検索クエリをサポートします。 これらのインデックスには、値が string または複数の string 配列である任意のフィールドを含めることができます。 MongoDB はさまざまな言語のテキスト検索をサポートしています。 インデックスの作成時に、オプションとしてデフォルト言語を指定できます。
Tip
MongoDB は、改良された全文検索ソリューションであるAtlas Searchを提供します。 Atlas Search インデックスとその使用方法の詳細については、このガイドの「 Atlas Search インデックス」セクションを参照してください。
シングル フィールド
次の例では、 plotフィールドに テキスト インデックスを作成しています。
try { val resultCreateIndex = moviesCollection.createIndex(Indexes.text(Movie::plot.name)) println("Index created: $resultCreateIndex") } catch (e: MongoCommandException) { if (e.errorCodeName == "IndexOptionsConflict") { println("there's an existing text index with different options") } }
Index created: plot_text
以下は、前のコード スニペットで作成されたインデックスによってカバーされるクエリの例です。 テキスト インデックスにはソート順序が含まれていないため、 sortは省略されていることに注意してください。
val filter = Filters.text("Batman") val projection = Projections.fields( Projections.include(Movie::fullplot.name), Projections.excludeId() ) data class Results(val fullplot: String) val resultsFlow = moviesCollection.find<Results>(filter).projection(projection) resultsFlow.collect { println(it) }
複数のフィールド
コレクションには 1 つのテキスト インデックスしか含めることができません。 複数のテキストフィールドのテキストインデックスを作成する場合は、複合インデックスを作成する必要があります。 複合インデックス内のすべてのテキスト フィールドに対してテキスト検索が実行されます。
次のスニペットは、 フィールドと フィールドの複合テキストtitle genreインデックスを作成します。
try { val resultCreateIndex = moviesCollection.createIndex( Indexes.compoundIndex( Indexes.text(Movie::title.name), Indexes.text(Movie::genres.name) ) ) println("Index created: $resultCreateIndex") } catch (e: MongoCommandException) { if (e.errorCodeName == "IndexOptionsConflict") { println("there's an existing text index with different options") } }
Index created: title_text_genre_text
詳細については、次のサーバー マニュアル エントリを参照してください。
地理空間インデックス
MongoDB は、 2 dsphere インデックスを使用した地理空間座標データのクエリをサポートしています。 2dsphereインデックスを使用すると、包含、交差、近接性について地理空間データを照会できます。 地理空間データのクエリの詳細については、サーバー マニュアルの「地理空間クエリ」を参照してください。
2dsphereインデックスを作成するには、 GeoJSON オブジェクトのみを含むフィールドを指定する必要があります。 このタイプの詳細については、サーバー マニュアルの 「 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インデックスを作成します。
val resultCreateIndex = theatersCollection.createIndex( Indexes.geo2dsphere("${Theater::location.name}.${Theater.Location::geo.name}") ) println("Index created: $resultCreateIndex")
Index created: location.geo_2dsphere
重要
すでに地理空間インデックスでカバーされているフィールドに地理空間インデックスを作成しようとすると、エラーが発生します。
以下は、前のコード スニペットで作成されたインデックスによってカバーされる地理空間クエリの例です。
// MongoDB Headquarters in New York, NY. val refPoint = Point(Position(-73.98456, 40.7612)) val filter = Filters.near( "${Theater::location.name}.${Theater.Location::geo.name}", refPoint, 1000.0, 0.0 ) val resultsFlow = theatersCollection.find(filter) resultsFlow.collect { println(it) }
MongoDB は、ユークリッド平面上の距離を計算するための 2d インデックスもサポートしています。詳細については、サーバー マニュアルの 地理空間クエリ を参照してください。
Unique Indexes
ユニークインデックスにより、インデックス フィールドに重複する値が格納されなくなります。デフォルトでは、MongoDB はコレクションの作成時に _id フィールドにユニークインデックスを作成します。ユニークインデックスを作成するには、重複を防ぐフィールドまたはフィールドの組み合わせを指定し、unique オプションを true に設定します。
次の例では、 theaterIdフィールドに一意の降順インデックスを作成しています。
try { val indexOptions = IndexOptions().unique(true) val resultCreateIndex = theatersCollection.createIndex( Indexes.descending(Theater::theaterId.name), indexOptions ) println("Index created: $resultCreateIndex") } catch (e: DuplicateKeyException) { println("duplicate field values encountered, couldn't create index: \t${e.message}") }
Index created: theaterId_-1
重要
一意なインデックスに違反する重複値を保存する書込み操作を実行すると、ドライバーはDuplicateKeyExceptionを発生させ、MongoDB は次のようなエラーを返します。
E11000 duplicate key error index
詳細については、MongoDB サーバー マニュアルの [一意のインデックス ] ページを参照してください。
クラスター化インデックス
クラスター化されたインデックスは、キー値の順にドキュメントを保存するようにコレクションに指示します。 クラスター化インデックスを作成するには、コレクションを作成するときに、 _idフィールドをキーとして指定し、一意のフィールドをtrueとして指定して、 クラスター化インデックス オプション を指定します。
次の例では、 vendorsコレクションの_idフィールドにクラスター化インデックスを作成しています。
val clusteredIndexOptions = ClusteredIndexOptions(Document("_id", 1), true) val createCollectionOptions = CreateCollectionOptions().clusteredIndexOptions(clusteredIndexOptions) database.createCollection("vendors", createCollectionOptions)
詳細については、MongoDB サーバーのマニュアル セクションを参照してください。
インデックスを削除する
_idフィールドのデフォルトの一意なインデックスを除く未使用のインデックスを削除できます。
次のセクションでは、インデックスを削除する方法を示します。
インデックス仕様ドキュメントの使用
インデックス付き名前フィールドの使用
ワイルドカード文字を使用してすべてのインデックスを削除する
インデックス仕様ドキュメントを使用したインデックスの削除
インデックス仕様ドキュメントをdropIndex()メソッドに渡して、コレクションからインデックスを削除します。 インデックス仕様ドキュメントは、指定されたフィールドのインデックスのタイプを指定するBsonインスタンスです。
次のスニペットは、 コレクションのtitleフィールドの昇順のインデックスを削除します。
moviesCollection.dropIndex(Indexes.ascending(Movie::title.name));
重要
テキスト インデックスを削除する場合は、代わりにインデックスの名前を使用する必要があります。 詳細については、「 名前フィールドを使用したインデックスの削除 」セクションを参照してください。
名前フィールドを使用したインデックスの削除
コレクションからインデックスを削除するには、インデックスのnameフィールドをdropIndex()メソッドに渡します。
インデックスの名前を見つける必要がある場合は、 listIndexes()メソッドを使用して、インデックス内のnameフィールドの値を確認します。
次のスニペットは、コレクション内のすべてのインデックスを検索して出力します。
val indexes = moviesCollection.listIndexes() indexes.collect { println(it.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" インデックスを削除します。
moviesCollection.dropIndex("title_text")
注意
複合テキスト インデックスから単一のフィールドを削除することはできません。 インデックス フィールドを更新するには、インデックス全体を削除し、新しいインデックスを作成する必要があります。
ワイルドカード文字を使用したインデックスの削除
コレクションでdropIndexes()メソッドを呼び出すと、すべてのインデックスを削除できます。
moviesCollection.dropIndexes()
以前のバージョンの MongoDB の場合は、コレクションのdropIndex()への呼び出しに「*」をパラメータとして渡します。
moviesCollection.dropIndex("*")
このセクションのメソッドの詳細については、次の API ドキュメントを参照してください。