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 la query
Cuando ejecutas una query en MongoDB, tu 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 orden para especificar el orden de los documentos devueltos de MongoDB (opcional)
Cuando todos los campos especificados en la query, proyección y orden están en el mismo índice, MongoDB devuelve los 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.
Considera 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, crea índices en los campos que aparecen con mayor frecuencia en las consultas de tu aplicación y en las operaciones que devuelven resultados ordenados.
Rastrea el uso de memoria y disco del índice para la planificación de la capacidad, ya que cada índice que añades consume espacio en disco y memoria cuando está activo.
Evite añadir índices que utilice con poca frecuencia. Tenga en cuenta que cuando una operación de escritura actualiza un campo indizado, 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 un solo campo e índices 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, mejorando la query y el rendimiento de 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 varias claves en los campos rated, genres (un arreglo de cadenas de texto) 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 de clave múltiple se comportan de manera diferente a otros índices en términos de cobertura de consultas, cálculo de límites del índice y comportamiento de ordenación. Para obtener más información sobre los índices multikey, incluyendo una discusión sobre su comportamiento y limitaciones, consulta Índices multikey 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 MongoDB Vector Search guide.
Puedes llamar a los siguientes métodos en una colección para gestionar tus índices de MongoDB Search y MongoDB Vector Search:
createSearchIndex()(válido solamente para índice de MongoDB Search)createSearchIndexes()listSearchIndexes()updateSearchIndex()dropSearchIndex()
Nota
Los métodos de gestión de índice de MongoDB Search se ejecutan de manera asíncrona. Los métodos del controlador pueden devolver antes de confirmar que se ejecutaron con éxito. Para determinar el estado actual de los índices, llama al método listSearchIndexes().
Las siguientes secciones muestran ejemplos de código que demuestran cómo utilizar cada uno de los métodos anteriores.
Crear un índice de búsqueda
Puedes utilizar el método createSearchIndex() para crear un único índice MongoDB Search. No puedes usar este método para crear un índice MongoDB Vector Search.
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 los í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) )
listSearchIndexes
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 permiten realizar queries de texto sobre contenido de string. Estos índices pueden incluir cualquier campo cuyo valor sea un string o un arreglo de elementos de tipo string. MongoDB soporta queries de texto para varios lenguajes. Puedes especificar el lenguaje por defecto como una opción 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 snippet 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 más información, consulta 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 aseguran que los campos indexados no almacenen valores duplicados. Por defecto, 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 en los que desea evitar la duplicación y configure la opción unique en 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 infringe el índice único, el controlador genera un DuplicateKeyException, y MongoDB lanza 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 instruyen a una colección para almacenar los documentos ordenados por un valor clave. Para crear un índice agrupado, especifica la opción de índice agrupado teniendo el campo _id como clave y el campo único como true cuando crees tu 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)
Consulta 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
Utilizar un carácter comodín para remover 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.
Remover un índice usando un campo de nombre
Pasa el campo name del índice al método dropIndex() para remover 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.
Remover un índice utilizando 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: