Overview
En esta guía, puedes aprender cómo crear y administrar índices utilizando el driver de MongoDB para Kotlin.
Los índices proporcionan soporte para la ejecución eficiente de queries en MongoDB. Sin índices, MongoDB debe escanear cada documento en una colección (un escaneo de colección) para encontrar los documentos que coinciden con cada consulta. Estos escaneos de colección son lentos y pueden afectar negativamente al rendimiento de su aplicación. Si existe un índice apropiado para una query, MongoDB puede usar el índice para limitar los documentos que la query debe inspeccionar.
Los índices también ofrecen los siguientes beneficios:
Los índices permiten una clasificación eficiente.
Los índices permiten capacidades especiales como consultas geoespaciales.
Los índices permiten la creación de restricciones para garantizar que el valor de un campo sea único.
Para obtener más información, consulta Índices en el manual del servidor.
Tip
Las operaciones de actualización usan índices para encontrar documentos que actualizar y las operaciones de borrado usan índices para encontrar documentos que borrar. Algunas etapas en el pipeline de agregación también utilizan índices para mejorar el rendimiento.
Cobertura y rendimiento de las consultas
Cuando ejecuta una consulta en MongoDB, su comando puede incluir varios elementos:
Criterios de consulta que especifican los campos y valores que buscas
Opciones que afectan la ejecución de la query, como el nivel de consistencia de lectura
Criterios de proyección para especificar los campos que MongoDB devuelve (opcional)
Criterios de ordenación para especificar el orden de los documentos devueltos desde MongoDB (opcional)
Cuando todos los campos especificados en la consulta, proyección y ordenación están en el mismo índice, MongoDB devuelve resultados directamente desde el índice, también llamado consulta cubierta.
Importante
Orden de clasificación
Los criterios de clasificación deben coincidir o invertir el orden del índice.
Considere un índice en el campo name en orden ascendente (A-Z) y age en orden descendente (9-0):
name_1_age_-1
MongoDB utiliza este índice cuando se ordenan tus datos de cualquiera de las siguientes maneras:
nameascendente,agedescendentenamedescendente,ageascendente
Especificar un orden de clasificación de name y age ascendente o name y age descendente requieren una clasificación en memoria.
Para obtener más información sobre cómo garantizar que tu índice cubra tus criterios de query y proyección, consulta los artículos del manual del servidor sobre cobertura de la query.
Consideraciones operativas
Las siguientes pautas describen cómo puedes optimizar la forma en que tu aplicación utiliza los índices:
Para mejorar el rendimiento de las consultas, cree índices en los campos que aparecen con frecuencia en las consultas y operaciones de su aplicación que devuelven resultados ordenados.
Realice un seguimiento del índice de uso de la memoria y del disco para planificar la capacidad, porque cada índice que agrega consume espacio en disco y memoria cuando está activo.
Evite agregar índices que use con poca frecuencia. Tenga en cuenta que, cuando una operación de escritura actualiza un campo indexado, MongoDB actualiza el índice relacionado.
Dado que MongoDB brinda soporte a esquemas dinámicos, las aplicaciones pueden realizar queries contra campos cuyos nombres no se pueden conocer de antemano o son arbitrarios. MongoDB 4.2 introdujo índices comodín para ayudar a respaldar estas consultas. Los índices comodín no están diseñados para reemplazar la planificación de índices basada en cargas de trabajo.
Para obtener más información sobre cómo diseñar su modelo de datos y elegir índices apropiados para su aplicación, consulte la documentación del servidor MongoDB sobre Estrategias de indexación y Modelado de datos e índices.
Tipos de índice
MongoDB admite varios tipos de índices diferentes para admitir la consulta de sus datos. Las siguientes secciones describen los tipos de índice más comunes y proporcionan código de muestra para crear cada tipo de índice. Para ver una lista completa de los tipos de índices, consulta Índices en el manual del servidor.
Tip
El controlador de Kotlin proporciona la clase Índices para crear y administrar índices. Esta clase incluye métodos de fábrica estáticos para crear documentos de especificación de índice para diferentes tipos de claves de índice de MongoDB.
Los siguientes ejemplos utilizan el método createIndex() para crear varios índices, y las siguientes clases de datos para modelar datos en 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 ) } }
Índices de campo único y compuestos
Índices de un solo campo
Índices de campo único son índices con una referencia a un solo campo dentro de los documentos de una colección. Mejoran el rendimiento de las queries de campo único y de la ordenación, y admiten Índices TTL que remueven automáticamente documentos de una colección tras un período de tiempo determinado o en un horario definido.
Nota
El índice _id_ es un ejemplo de un índice de un solo campo. Este índice se crea automáticamente en el campo _id cuando se crea una nueva colección.
El siguiente ejemplo crea un índice en orden ascendente en el campo title:
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::title.name)) println("Index created: $resultCreateIndex")
Index created: title_1
El siguiente es un ejemplo de una query que está cubierta por el índice creado en el snippet de código anterior:
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) }
Consulta la sección del manual de servidor de MongoDB sobre índices de campo único para obtener más información.
Índices compuestos
Los índices compuestos contienen referencias a múltiples campos dentro de los documentos de una colección, lo que mejora el rendimiento de las consultas y la clasificación.
Tip
Lee más sobre índices compuestos, prefijos de índice y orden de clasificación aquí.
El siguiente ejemplo crea un índice compuesto en los campos type y rated:
val resultCreateIndex = moviesCollection.createIndex(Indexes.ascending(Movie::type.name, Movie::rated.name)) println("Index created: $resultCreateIndex")
Index created: type_1_rated_1
El siguiente es un ejemplo de una query que está cubierta por el índice creado en el snippet de código anterior:
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) }
Consulta la sección del manual del servidor de MongoDB sobre Índices compuestos para obtener más información.
Índices multiclave (índices en campos de arreglos)
Los índices multiclave son índices que mejoran el rendimiento de las queries que especifican un campo con un índice que contiene un valor de arreglo. Puedes definir un índice multiclave utilizando la misma sintaxis que un índice de campo único o compuesto.
El siguiente ejemplo crea un índice compuesto de múltiples claves en los campos rated, genres (una matriz de cadenas) y 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
El siguiente es un ejemplo de una query que está cubierta por el índice creado en el snippet de código anterior:
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) }
Los índices multiclave se comportan de forma diferente a otros índices en cuanto a la cobertura de consultas, el cálculo de los límites de índice y el comportamiento de ordenación. Para obtener más información sobre los índices multiclave, incluyendo una explicación de su comportamiento y limitaciones, consulte Índices multiclave en el manual del servidor.
MongoDB Search e MongoDB Vector Search Indexes
Puedes gestionar programáticamente tus índices de MongoDB Search y MongoDB Vector Search utilizando el controlador de Kotlin.
La funcionalidad de búsqueda de MongoDB permite realizar búsquedas de texto completo en colecciones alojadas en MongoDB. Para obtener más información sobre MongoDB Search, consulte la documentación de Índices de MongoDB Search.
MongoDB Vector Search permite realizar búsquedas semánticas sobre embeddings de vectores almacenados en MongoDB. Para obtener más información sobre MongoDB Vector Search, consulte Guíade búsqueda vectorial de MongoDB.
Puede llamar a los siguientes métodos en una colección para administrar sus índices MongoDB Search y MongoDB Vector Search:
createSearchIndex()(válido solo para índices de búsqueda de MongoDB)createSearchIndexes()listSearchIndexes()updateSearchIndex()dropSearchIndex()
Nota
Los métodos de gestión de índices de MongoDB Search se ejecutan de forma asíncrona. Los métodos del controlador pueden regresar antes de confirmar su correcta ejecución. Para determinar el estado actual de los índices, llame al método listSearchIndexes().
Las siguientes secciones proporcionan ejemplos de código que demuestran cómo utilizar cada uno de los métodos anteriores.
Crear un índice de búsqueda
Puede usar el método createSearchIndex() para crear un único índice de búsqueda de MongoDB. No puede usar este método para crear un índice de búsqueda vectorial de MongoDB.
Puedes utilizar el createSearchIndexes() para crear varios índices de MongoDB Search o MongoDB Vector Search. Debe crear una instancia de SearchIndexModel para cada índice y luego pasar una lista de instancias SearchIndexModel al método createSearchIndexes().
El siguiente ejemplo de código muestra cómo crear un índice de búsqueda de MongoDB:
val searchIdx = Document( "mappings", Document("dynamic", true) ) val resultCreateIndex = moviesCollection.createSearchIndex("myIndex", searchIdx)
Para crear varios índices de búsqueda o Vector Search, debes crear una instancia de SearchIndexModel para cada índice.
El siguiente ejemplo de código muestra cómo crear índices de búsqueda y búsqueda vectorial en una sola llamada:
val searchIdxMdl = SearchIndexModel( "searchIdx", Document("analyzer", "lucene.standard").append( "mappings", Document("dynamic", true) ), SearchIndexType.search() ) val vectorSearchIdxMdl = SearchIndexModel( "vsIdx", Document( "fields", listOf( Document("type", "vector") .append("path", "embeddings") .append("numDimensions", 1536) .append("similarity", "dotProduct") ) ), SearchIndexType.vectorSearch() ) val resultCreateIndexes = moviesCollection.createSearchIndexes( listOf(searchIdxMdl, vectorSearchIdxMdl) )
Índices de búsqueda de listas
Puede utilizar el método listSearchIndexes() para devolver una lista de los índices de búsqueda de MongoDB Search en una colección.
El siguiente ejemplo de código muestra cómo imprimir una lista de los índices de búsqueda en una colección:
val searchIndexesList = moviesCollection.listSearchIndexes().toList()
Actualizar un índice de búsqueda
Puedes utilizar el método updateSearchIndex() para actualizar un índice de Búsqueda de MongoDB.
El siguiente código muestra cómo actualizar un índice de búsqueda:
moviesCollection.updateSearchIndex( "myIndex", Document("analyzer", "lucene.simple").append( "mappings", Document("dynamic", false) .append( "fields", Document( "title", Document("type", "string") ) ) ) )
Eliminar un índice de búsqueda
Puedes usar el método dropSearchIndex() para remover un índice de MongoDB Search.
El siguiente código muestra cómo eliminar un índice de búsqueda de una colección:
moviesCollection.dropSearchIndex("myIndex");
Text Indexes
Los índices de texto admiten consultas de texto sobre contenido de cadena. Estos índices pueden incluir cualquier campo cuyo valor sea una cadena o un array de elementos de cadena. MongoDB admite consultas de texto en varios idiomas. Puede especificar el idioma predeterminado al crear el índice.
Tip
MongoDB ofrece una solución mejorada de búsqueda de texto completo, MongoDB Search. Para aprender más sobre los índices de búsqueda de MongoDB y cómo utilizarlos, consulta la sección MongoDB Search y MongoDB Vector Search Indexes de esta guía.
Campo único
El siguiente ejemplo crea un índice de texto en el campo 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
El siguiente es un ejemplo de una query cubierto por el índice creado en el snippet de código anterior. Ten en cuenta que se omite el sort porque los índices de texto no contienen orden de clasificación.
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) }
Campos múltiples
Una colección solo puede contener un índice de texto. Si quieres crear un índice de texto para varios campos de texto, debes crear un índice compuesto. Una query de texto se ejecuta en todos los campos de texto dentro del índice compuesto.
El siguiente fragmento crea un índice de texto compuesto para los campos title y 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
Para obtener más información, consulte las siguientes entradas del Manual del servidor:
Índices geoespaciales
MongoDB admite consultas de datos de coordenadas geoespaciales utilizando 2índices dsphere. Con un 2dsphere índice, puedes query los datos geoespaciales para inclusión, intersección y proximidad. Para obtener más información sobre la consulta de datos geoespaciales, consulte Consultas geoespaciales en el manual del servidor.
Para crear un índice 2dsphere, debes especificar un campo que contenga solo objetos GeoJSON. Para obtener más información sobre este tipo, consulta Objetos GeoJSON en el manual del servidor.
El campo location.geo en el siguiente documento de ejemplo de la colección theaters en la base de datos sample_mflix es un objeto punto GeoJSON que describe las coordenadas del teatro:
{ "_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 ] } } }
El siguiente ejemplo crea un índice 2dsphere en el campo location.geo:
val resultCreateIndex = theatersCollection.createIndex( Indexes.geo2dsphere("${Theater::location.name}.${Theater.Location::geo.name}") ) println("Index created: $resultCreateIndex")
Index created: location.geo_2dsphere
Importante
El intento de crear un índice geoespacial en un campo que ya está cubierto por un índice geoespacial resulta en un error.
El siguiente es un ejemplo de una query geoespacial que está cubierta por el índice creado en el snippet de código anterior:
// 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 también admite índices 2d para calcular distancias en un plano euclidiano. Para obtener más información, consulte Consultas geoespaciales en el manual del Servidor.
Unique Indexes
Los índices únicos garantizan que los campos indexados no almacenen valores duplicados. De forma predeterminada, MongoDB crea un índice único en el campo _id durante la creación de una colección. Para crear un índice único, especifique el campo o la combinación de campos que desea evitar la duplicación y configure la opción unique como true.
El siguiente ejemplo crea un índice descendente único en el campo 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
Importante
Si realiza una operación de escritura que almacena un valor duplicado que viola el índice único, el controlador genera un DuplicateKeyException y MongoDB arroja un error similar al siguiente:
E11000 duplicate key error index
Consulta la página de Índices Únicos en el manual del servidor de MongoDB para obtener más información.
Índices clusterizados
Los índices agrupados indican a una colección que almacene documentos ordenados por un valor de clave. Para crear un índice agrupado, especifique la opción de índice agrupado con el _id campo como clave y el campo único al true crear la colección.
El siguiente ejemplo crea un índice clusteringado en el campo _id de la colección vendors:
val clusteredIndexOptions = ClusteredIndexOptions(Document("_id", 1), true) val createCollectionOptions = CreateCollectionOptions().clusteredIndexOptions(clusteredIndexOptions) database.createCollection("vendors", createCollectionOptions)
Consulte las secciones del manual del servidor MongoDB para obtener más información:
Remover un índice
Puedes remover cualquier índice no utilizado, excepto el índice único por defecto en el campo _id.
Las siguientes secciones muestran las formas de remover índices:
Uso de un documento de especificación de índice
Uso de un campo de nombre indexado
Usando un carácter comodín para eliminar todos los índices
Remover un índice utilizando un documento de especificación de índice
Pase un documento de especificación del índice al método dropIndex() para remover un índice de una colección. Un documento de especificación del índice es una instancia de Bson que especifica el tipo de índice en un campo determinado.
El siguiente snippet elimina un índice ascendente en el campo title de una colección:
moviesCollection.dropIndex(Indexes.ascending(Movie::title.name));
Importante
Si quieres descartar un índice de texto, debes usar el nombre del índice en su lugar. Consulta la sección Remover un índice usando un campo Nombre para más detalles.
Eliminar un índice mediante un campo de nombre
Pase el campo name del índice al método dropIndex() para eliminar un índice de una colección.
Si necesita encontrar el nombre de su índice, use el método listIndexes() para ver el valor de los campos name en sus índices.
El siguiente snippet recupera e imprime todos los índices de una colección:
val indexes = moviesCollection.listIndexes() indexes.collect { println(it.toJson()) }
Si llamas a listIndex() en una colección que contiene un índice de texto, la salida podría parecerse a la siguiente:
{ "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 }
Esta salida nos dice que los nombres de los índices existentes son "_id" y "title_text".
El siguiente snippet remueve el índice "title_text" de la colección:
moviesCollection.dropIndex("title_text")
Nota
No puedes remover un solo campo de un índice de texto compuesto. Debes descartar el índice completo y crear uno nuevo para actualizar los campos indexados.
Eliminar un índice usando un carácter comodín
A partir de MongoDB 4.2, puede eliminar todos los índices llamando al método dropIndexes() en su colección:
moviesCollection.dropIndexes()
Para versiones anteriores de MongoDB, pasa "*" como parámetro en tu llamada a dropIndex() en tu colección:
moviesCollection.dropIndex("*")
Para obtener más información sobre los métodos de esta sección, consulte la siguiente Documentación de la API: