Overview
在本指南中,您可以学习如何使用 MongoDB Scala 驱动程序创建和管理索引。
MongoDB 中的索引支持高效执行查询。如果没有索引,MongoDB 必须执行集合扫描,读取集合中的每个文档以找到查询匹配项。集合扫描会降低应用程序的性能。如果查询存在适当的索引,MongoDB 就可以使用该索引来限制必须检查的文档。
索引还可实现以下功能:
高效分类
地理空间搜索
提示
MongoDB 还在查找用于更新操作和删除操作的文档时使用索引。聚合管道中的某些阶段也使用索引来提高性能。
查询覆盖和性能
对 MongoDB 执行查询时,您的命令可以包含以下元素:
用于指定您要查找的字段和值的查询条件
影响查询执行的选项,例如读关注
指定 MongoDB 返回的字段的投影条件(可选)
指定返回文档顺序的排序标准(可选)
当查询、投影和排序中的所有字段均位于同一索引时,MongoDB 会直接从索引返回结果。此过程称为覆盖查询。
重要
排序顺序
排序条件必须与索引的顺序一致或相反。
举例来说,以下索引指定字段 name 按升序 (AZ) 排序而 {2} 按降序 (9-0) 排序:
name_1_age_-1
当您按以下任一方式对数据进行排序时,MongoDB 会使用此索引:
name升序,age降序name降序,age升序
将 name 和 age 都指定为升序或都指定为降序需要进行内存中排序。
有关索引覆盖的更多信息,请参阅MongoDB Server手册中的 查询优化。
操作注意事项
以下指南描述了如何优化应用程序使用索引的方式:
若要提高查询性能,请对应用程序查询中经常出现的字段以及其他操作返回的排序结果中经常出现的字段构建索引。
追踪索引内存和磁盘使用情况以进行容量规划,因为您添加的每个索引在活动时都会消耗磁盘空间和内存。
避免添加不常用的索引。请注意,当写入操作更新索引的字段时,MongoDB 会更新相关索引。
由于 MongoDB 支持动态模式,因此应用程序可以查询事先无法知道名称或具有任意名称的字段。MongoDB 4.2 引入了通配符索引,以帮助支持这些查询。通配符索引并不是为了取代基于工作负载的索引规划而设计的。
有关设计数据模型和选择适合应用程序的索引的更多信息,请参阅有关“索引策略”和“数据建模和索引”的 MongoDB 服务器文档。
示例应用程序
您可以使用以下示例应用程序来测试此页面上的代码。 要使用示例应用程序,请执行以下步骤:
确保项目中安装了Scala驱动程序。请参阅下载和安装指南以学习;了解更多信息。
复制以下代码并将其粘贴到新的
.scala文件中。从此页面复制代码示例,并将其粘贴到文件中的指定行。
import org.mongodb.scala._ import org.mongodb.scala.model.SearchIndexModel import java.util.concurrent.TimeUnit import scala.concurrent.Await import scala.concurrent.duration.Duration import org.mongodb.scala.model.Indexes object SearchIndexes { def main(args: Array[String]): Unit = { // Create a new client and connect to the server val mongoClient = MongoClient("<connection string URI>") val database = mongoClient.getDatabase("<database name>") val collection = database.getCollection("<collection name>") // Start example code here // End example code here Thread.sleep(1000) mongoClient.close() } }
样本数据
本指南中的示例使用Atlas示例数据集的 sample_mflix数据库中的 movies集合。要学习如何创建免费的MongoDB Atlas 集群并加载示例数据集,请参阅Atlas入门。
索引类型
MongoDB 支持多种不同的索引类型来支持数据查询。 以下部分描述了最常见的索引类型,并提供了创建每种索引类型的示例代码。 有关索引类型的完整列表,请参阅 MongoDB Server手册中的 索引 。
单字段索引
单字段索引是对集合文档中的单字段进行引用的索引。其提高了单字段查询和排序性能,并支持 TTL 索引,可在一定时间后或特定时钟时间自动从集合中删除文档。
注意
_id_ 索引是单字段索引的一个示例。创建新集合时,会在 _id 字段上自动创建此索引。
以下示例在指定字段上创建一个升序索引:
val index = Indexes.ascending("<field name>") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
要运行本节中的以下示例,必须在文件中包含以下 import 声明:
import org.mongodb.scala._ import org.mongodb.scala.model.Indexes import org.mongodb.scala.model.IndexOptions._ import org.mongodb.scala.model.Filters._ import scala.concurrent.Await import scala.concurrent.duration._ import scala.util.{Failure, Success} import java.util.concurrent.TimeUnit
使用createIndex()方法创建单字段索引。 以下示例在title字段上按升序创建索引:
val index = Indexes.ascending("title") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
您可以使用 listIndexes() 方法验证索引是否已创建。 您应该会在列表中看到 title 的索引,如以下输出所示:
collection.listIndexes().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"v": 2, "key": {"title": 1}, "name": "title_1"}
以下是在 title字段上创建的索引涵盖的查询示例:
val filter = equal("title", "Sweethearts") collection.find(filter).first().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"_id":...,"plot":"A musical comedy duo...", "genres":["Musical"],...,"title":"Sweethearts",...}
复合索引
复合索引包含对集合文档中多个字段的引用,从而提高查询和排序性能。
以下示例在两个指定字段上创建复合索引。
val index = Indexes.compoundIndex( Indexes.descending("<field name 1>"), Indexes.ascending("<field name 2>") ) val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
要运行本节中的以下示例,必须在文件中包含以下 import 声明:
import org.mongodb.scala._ import org.mongodb.scala.model.Indexes import org.mongodb.scala.model.IndexOptions._ import org.mongodb.scala.model.Filters._ import scala.concurrent.Await import scala.concurrent.duration._ import scala.util.{Failure, Success} import java.util.concurrent.TimeUnit
使用 createIndex() 方法创建复合索引。 以下示例按降序对 runtime字段创建索引,并按升序对 year字段创建索引:
val index = Indexes.compoundIndex(Indexes.descending("runtime"), Indexes.ascending("year")) val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
您可以使用 listIndexes() 方法验证索引是否已创建。 您应该在列表中看到 runtime 和 year 的索引,如以下输出所示:
collection.listIndexes().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"v": 2, "key": {"runtime": -1, "year": 1}, "name": "runtime_-1_year_1"}
以下是在 runtime 和 year 字段上创建的索引涵盖的查询示例:
val filter = and(gt("runtime", 80), gt("year", 1999)) collection.find(filter).first().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"_id":...,"runtime": 98,...,"title": "In the Mood for Love",...,"year": 2000,...}
Multikey Indexes
多键索引是提高对数组值字段的查询性能的索引。您可以使用 createIndex() 方法和用于创建 单字段索引的相同语法在集合上创建多键索引。
创建多键索引时,必须指定以下详细信息:
要在其上创建索引的字段
每个字段的排序顺序(升序或降序)
以下示例在指定的数组值字段上创建多键索引:
val index = Indexes.ascending("<field name>") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
要运行本节中的以下示例,必须在文件中包含以下 import 声明:
import org.mongodb.scala._ import org.mongodb.scala.model.Indexes import org.mongodb.scala.model.IndexOptions._ import org.mongodb.scala.model.Filters._ import scala.concurrent.Await import scala.concurrent.duration._ import scala.util.{Failure, Success} import java.util.concurrent.TimeUnit
使用 createIndex() 方法创建多键索引。 以下示例在 cast字段上按升序创建索引:
val index = Indexes.ascending("cast") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
您可以通过调用 listIndexes() 方法验证索引是否已创建。 您应该会在列表中看到 cast 的索引,如以下输出所示:
collection.listIndexes().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"v": 2, "key": {"cast": 1}, "name": "cast_1"}
以下是在 cast字段上创建的索引涵盖的查询示例:
val filter = and(equal("cast", "Aamir Khan"), equal("cast", "Kajol")) collection.find(filter).first().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"_id":...,"title":"Fanaa",...,"cast": ["Aamir Khan", "Kajol", "Rishi Kapoor", "Tabu"],...}
MongoDB 搜索 和 MongoDB Vector 搜索索引
MongoDB 搜索 使您能够对 MongoDB Atlas 上托管的集合执行全文搜索。MongoDB 搜索索引指定搜索行为以及要索引的字段。
MongoDB 向量搜索使您能够对存储在 MongoDB 中的向量嵌入执行语义搜索。要了解有关 MongoDB Vector Search 的更多信息,请参阅 MongoDB Vector Search 概述。
您可以在集合上调用以下方法来管理MongoDB Search 和MongoDB Vector Search 索引:
createSearchIndex()createSearchIndexes()listSearchIndexes()updateSearchIndex()dropSearchIndex()
注意
上述索引管理方法异步运行,并且可能会在确认其成功运行之前返回。要确定索引的当前状态,请调用 listSearchIndexes() 方法。
创建搜索和向量搜索索引
您可以使用 createSearchIndex() 和 createSearchIndexes() 方法创建一个或多个 MongoDB Search 或 MongoDB 向量搜索索引。createSearchIndexes() 方法接受索引定义列表,这使您可以在一次调用中创建多个索引,并为每个索引指定索引类型。
以下代码示例展示了如何创建MongoDB搜索索引:
val index = Document("mappings" -> Document("dynamic" -> true)) collection.createSearchIndex("<index name>", index) .subscribe((result: String) => ())
使用 createSearchIndexes() 方法创建多个 MongoDB Search 或 MongoDB Vector Search 索引。
以下代码示例展示了如何在一次调用中创建 MongoDB Search 和 MongoDB Vector Search 搜索索引:
val searchIdxMdl = SearchIndexModel( Option("searchIdx"), Document("analyzer" -> "lucene.standard", "mappings" -> Document("dynamic" -> true)), Option(SearchIndexType.search()) ) val vectorSearchIdxMdl = SearchIndexModel( Option("vsIdx"), Document( "fields" -> List( Document("type" -> "vector", "path" -> "embeddings", "numDimensions" -> 1536, "similarity" -> "dotProduct") ) ), Option(SearchIndexType.vectorSearch()) ) collection.createSearchIndexes(List(searchIdxMdl, vectorSearchIdxMdl)) .subscribe((result: String) => ())
要了解有关用于定义MongoDB Search 索引的语法的更多信息,请参阅Atlas手册中的索引参考指南。
搜索索引列表
您可以使用 listSearchIndexes() 方法返回集合中的所有 MongoDB 搜索索引。
以下代码示例演示如何通过订阅 listSearchIndexes() 方法返回的 Observable 来打印集合中的搜索索引列表:
collection.listSearchIndexes() .subscribe((result: Document) => println(result.toJson()))
{"id": "...", "name": "<index name 1>", "type": "search", "status": "READY", "queryable": true, ... } {"id": "...", "name": "<index name 2>", "type": "search", "status": "READY", "queryable": true, ... }
更新搜索索引
您可以使用 updateSearchIndex() 方法更新 MongoDB 搜索索引。
以下代码展示如何更新搜索索引:
val updateIndex = Document("mappings" -> Document("dynamic" -> false)) collection.updateSearchIndex("<index to update>", updateIndex) .subscribe((result: Unit) => ())
删除搜索索引
您可以使用 dropSearchIndex() 方法删除 MongoDB 搜索索引。
警告
删除搜索索引和集群是不可逆的
删除搜索索引和相关集群是永久操作。MongoDB 不支持恢复已删除的搜索索引或数据。在继续操作之前,请确保您已采取了适当措施,例如创建备份,以避免数据丢失。
MongoDB 不支持恢复已删除的搜索索引或数据的请求。您负责数据完整性和配置。
以下代码展示了如何从集合中删除搜索索引:
collection.dropSearchIndex("<index name>") .subscribe((result: Unit) => ())
地理空间索引
以下示例在包含GeoJSON对象的指定字段上创建2 dsphere索引:
val observable = collection.createIndex(Indexes.geo2dsphere("<2d index>")) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
有关2 dsphere 索引的更多信息,请参阅MongoDB Server手册中的2 dsphere 索引指南。
有关GeoJSON类型的更多信息,请参阅MongoDB Server手册中的GeoJSON对象指南。
删除索引
您可以删除针对 _id 字段的所有未使用索引,但默认唯一索引除外。
以下示例删除具有指定名称的索引:
val observable = collection.dropIndex("<index name>") Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
API 文档
要学习;了解有关本指南中使用的方法或对象的更多信息,请参阅以下API文档: