“文档” 菜单
文档首页
/ / /
Java (Sync) 驱动程序
/

索引

在此页面上

  • 概述
  • 查询覆盖和性能
  • 操作注意事项
  • 索引类型
  • 单字段索引和复合索引
  • 多键索引(数组字段索引)
  • Atlas Search 索引
  • 文本索引
  • 地理空间索引
  • 唯一索引
  • 通配符索引 (Wildcard Indexes)
  • 聚集索引
  • 删除索引
  • 使用索引规范文档删除索引
  • 使用名称字段删除索引
  • 使用通配符删除索引

在本指南中,您可以学习如何通过 MongoDB Java 驱动程序使用索引

MongoDB 中的索引支持高效执行查询。如果没有索引,MongoDB 必须扫描集合中的每个文档(集合扫描),才能找到与每个查询匹配的文档。这些集合扫描很慢,可能会对应用程序的性能产生负面影响。如果查询存在适当的索引,MongoDB 就可以使用该索引来限制必须检查的文档。

索引还:

  • 支持高效分类

  • 启用地理空间搜索等特殊功能

  • 支持添加约束,确保字段值唯一

  • 还有更多

提示

更新操作查找要更新的文档时、删除操作查找要删除的文档时以及聚合管道中的某些阶段也会使用索引。

对 MongoDB 执行查询时,您的命令可以包含各种元素:

  • 用于指定您要查找的字段和值的查询条件

  • 影响查询执行的选项,例如读关注

  • 用于指定 MongoDB 返回的字段的投影条件(可选)

  • 排序标准,用于指定从 MongoDB 返回文档的顺序(可选)

当查询、投影和排序中指定的所有字段均位于同一索引时,MongoDB 会直接从此索引返回结果,而这也被称为覆盖查询

重要

排序顺序

排序条件必须与索引的顺序一致或相反。

考虑字段上的索引, name按升序 (AZ) 排列,而age按降序 (9-0) 排列:

name_1_age_-1

当您按以下任一方式对数据进行排序时,MongoDB 会使用此索引:

  • name 升序, age降序

  • name 降序,age 升序

指定 nameage 升序或 nameage 降序排序需要进行内存中排序。

有关如何确保索引涵盖查询条件和投影的更多信息,请参阅 MongoDB 手册中有关查询覆盖范围的文章。

若要提高查询性能,请对应用程序查询中经常出现的字段以及其他操作返回的排序结果中经常出现的字段建立索引。您添加的每个索引在活动状态下都会占用磁盘空间和内存,因此您应当跟踪索引内存和磁盘使用情况以进行容量规划。此外,当写入操作更新索引化字段时,MongoDB 还须更新相关索引。

由于 MongoDB 支持动态模式,因此应用程序可以查询事先无法知道名称或具有任意名称的字段。MongoDB 4.2 引入了通配符索引,以帮助支持这些查询。通配符索引并不是为了取代基于工作负载的索引规划而设计的。

有关设计数据模型和选择适合应用程序的索引的更多信息,请参阅 MongoDB Server 数据建模和索引。

MongoDB 支持多种索引类型来进行数据查询。以下部分描述了最常见的索引类型,并提供了创建每种索引类型的示例代码。有关索引类型的完整列表,请参阅索引

提示

MongoDB Java 驱动程序提供 索引 类,其中包含用于为不同 MongoDB 索引键类型创建索引规范文档的静态工厂方法。

以下示例使用 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);

有关更多信息,请参阅 MongoDB Server 手册中的单字段索引

复合索引保存对集合文档中多个字段的引用,从而提高查询和排序性能。

提示

此处阅读有关复合索引、索引前缀和排序顺序的更多信息。

以下示例在 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 手册中的复合索引

多键索引可提高使用包含数组值的索引指定字段的查询性能。您可以使用与单字段或复合索引相同的语法定义多键索引。

以下示例在 ratedgenres(字符串数组)和 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 功能使您能够对 MongoDB Atlas 上托管的集合执行全文搜索。索引指定了搜索行为以及要索引的字段。

要了解有关 MongoDB Atlas Search 的更多信息,请参阅Atlas Search 索引文档。

您可以在集合上调用以下方法来管理 Atlas Search 索引:

  • createSearchIndex()

  • createSearchIndexes()

  • listSearchIndexes()

  • updateSearchIndex()

  • dropSearchIndex()

注意

Atlas Search 索引管理方法异步运行。驱动程序方法可以在确认成功运行前返回。要确定索引的当前状态,请调用 listSearchIndexes() 方法。

以下各节将提供代码示例,演示如何使用上述每种方法。

您可以使用 createSearchIndex() createSearchIndexes() 创建 Atlas Search 索引的方法。

以下代码示例展示了如何创建单个索引:

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");

文本索引支持对字符串内容进行文本搜索查询。这些索引可以包括任何值为字符串或字符串元素数组的字段。MongoDB 还支持各种语言的文本搜索。在创建索引时,可以指定默认语言作为选项。

提示

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);

一个集合只能包含一个文本索引。如果要为多个文本字段创建文本索引,必须创建复合索引。文本搜索在复合索引内的所有文本字段上运行。

以下代码段为 titlegenre 字段创建复合文本索引:

collection.createIndex(Indexes.compoundIndex(Indexes.text("title"), Indexes.text("genre")));

如需了解更多信息,请参阅以下“服务器手册条目”:

MongoDB 支持使用 2dsphere 索引查询地理空间坐标数据。借助 2dsphere 索引,您可以针对地理空间数据进行包含、相交和邻近范围方面的查询。有关查询地理空间数据的更多信息,请参阅地理空间查询

要创建2dsphere索引,您必须指定仅包含GeoJSON 对象的字段。有关此类型的更多详细信息,请参阅有关GeoJSON 对象的 MongoDB Server 手册页面。

以下样本文档中的 location.geo 字段来自 sample_mflix 数据库中的 theaters 集合,且为用于描述影院坐标的 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 还支持 2d 索引,用于计算欧几里德平面上的距离,以及处理 MongoDB 2.2 及更早版本中使用的“旧版坐标对”语法。有关更多信息,请参阅 MongoDB Server 手册中的“地理空间查询”页面

唯一索引可确保索引字段不存储重复值。默认情况下,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

有关更多信息,请参阅 MongoDB Server 手册中的“唯一索引”页面。

通配符索引可对未知或任意字段进行查询。如果您使用的是动态模式,则这些索引可能很有用。

以下示例将对 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 文档:

← 聚合表达式操作