文档菜单
文档首页
/ / /
Java 同步驱动
/

索引

本页内容

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

在本指南中,您可以了解如何使用 MongoDB Java 驱动程序中的 索引

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

索引还

  • 允许高效排序

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

  • 允许添加约束以确保字段值 唯一

  • 以及 更多

提示

索引还用于更新操作在查找要更新的文档时,删除操作在查找要删除的文档时,以及在聚合管道的 某些阶段

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

  • 查询条件,指定要查找的字段和值

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

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

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

当查询、投影和排序中指定的所有字段都在同一个索引中时,MongoDB直接从索引返回结果,也称为覆盖查询

重要

排序顺序

排序标准必须与索引的顺序匹配或相反。

考虑一个字段索引name按照升序(A-Z)和age按照降序(9-0)

name_1_age_-1

MongoDB在以下情况下使用此索引进行排序

  • name升序,age降序

  • name降序,age升序

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

有关确保索引覆盖查询标准和投影的更多信息,请参阅MongoDB手册中的关于查询覆盖的文章。

为了提高查询性能,在应用程序查询和返回排序结果的操作中经常出现的字段上建立索引。您添加的每个索引在活动时都会消耗磁盘空间和内存,因此我们建议您跟踪索引的内存和磁盘使用情况以进行容量规划。此外,当写操作更新索引字段时,MongoDB也会更新相关索引。

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

有关设计数据模型和选择适用于您的应用程序的索引的更多信息,请参阅MongoDB服务器数据建模和索引

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

提示

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

以下示例使用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 服务器手册中的单字段索引

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

提示

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

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

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

以下示例在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手册中的多键索引页面

您可以使用 Java 驱动程序以编程方式管理 Atlas 搜索和 Atlas 向量搜索索引。

Atlas 搜索功能使您能够对托管在 MongoDB Atlas 上的集合执行全文搜索。有关 MongoDB Atlas 搜索的更多信息,请参阅 Atlas 搜索索引 文档。

Atlas 向量搜索使您能够对存储在 MongoDB Atlas 中的向量嵌入执行语义搜索。有关 Atlas 向量搜索的更多信息,请参阅Atlas 向量搜索 部分。

您可以在集合上调用以下方法来管理您的 Atlas 搜索和向量搜索索引

  • createSearchIndex() (仅适用于 Atlas 搜索索引)

  • createSearchIndexes()

  • listSearchIndexes()

  • updateSearchIndex()

  • dropSearchIndex()

注意

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

以下部分提供了代码示例,展示了如何使用前面提到的每个方法。

您可以使用 createSearchIndex() 方法来创建 Atlas Search 索引。您 不能 使用此方法创建向量搜索索引。

以下代码示例展示了如何创建 Atlas Search 索引

Document searchIdx = new Document("mappings",
new Document("dynamic", true));
collection.createSearchIndex("myIndex", searchIdx);

您可以使用 createSearchIndexes() 方法来创建多个 Atlas Search 索引或一个或多个向量搜索索引。您必须为每个索引创建并传递一个 SearchIndexModel 实例。

以下代码示例展示了如何在一次调用中创建搜索和向量搜索索引

SearchIndexModel searchIdxMdl = new SearchIndexModel(
"searchIdx",
new Document("analyzer", "lucene.standard").append(
"mappings", new Document("dynamic", true)),
SearchIndexType.search()
);
SearchIndexModel vectorSearchIdxMdl = new SearchIndexModel(
"vsIdx",
new Document(
"fields",
Arrays.asList(
new Document("type", "vector")
.append("path", "embeddings")
.append("numDimensions", 1536)
.append("similarity", "dotProduct")
)
),
SearchIndexType.vectorSearch()
);
collection.createSearchIndexes(
Arrays.asList(searchIdxMdl, vectorSearchIdxMdl)
);

您可以使用 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 对象 的字段。有关此类类型的更多详细信息,请参阅 MongoDB 服务器手册中关于 GeoJSON 对象。

以下示例文档中 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 还支持用于在欧几里得平面上计算距离和用于与 MongoDB 2.2 及更早版本中使用的 "旧坐标对" 语法一起使用的 2d 索引。有关更多信息,请参阅 MongoDB 服务器手册中的 地理空间查询页面。

唯一索引确保索引的字段不存储重复值。默认情况下,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服务器手册中的唯一索引页面。

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

以下示例创建了一个在_location字段的所有值上的升序通配符索引,包括嵌套在子文档和数组中的值

String resultCreateIndex = collection.createIndex(Indexes.ascending("location.$**"));
System.out.println(String.format("Index created: %s", resultCreateIndex));

有关更多信息,请参阅MongoDB服务器手册中的通配符索引页面。

聚集索引指示集合根据键值对存储文档。要创建聚集索引,在创建集合时,指定聚集索引选项,以_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服务器手册中的章节

您可以删除任何未使用的索引,但不能删除_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文档。

返回

聚合表达式