Docs 菜单

Docs 主页开发应用程序MongoDB 驱动程序Go 驱动程序

搜索文本

在此页面上

  • 概述
  • 样本数据
  • 文本索引
  • 文本搜索(Text Search)
  • 按术语搜索
  • 按短语搜索
  • 排除术语搜索
  • 按相关性排序
  • 聚合(Aggregation)
  • 匹配搜索词
  • 按相关性排序
  • 更多信息
  • API 文档

在本指南中,您可以了解如何运行文本搜索。

重要

MongoDB 文本搜索与Atlas Search 不同。

本部分的示例使用以下 Dish 结构作为 menu 集合中文档的模型:

type Dish struct {
Name string
Description string
}

要运行本部分中的示例,请使用以下代码段将样本数据加载到 db.menu 集合中:

coll := client.Database("db").Collection("menu")
docs := []interface{}{
Dish{Name: "Shepherd’s Pie", Description: "A vegetarian take on the classic dish that uses lentils as a base. Serves 2."},
Dish{Name: "Green Curry", Description: "A flavorful Thai curry, made vegetarian with fried tofu. Vegetarian and vegan friendly."},
Dish{Name: "Herbed Whole Branzino", Description: "Grilled whole fish stuffed with herbs and pomegranate seeds. Serves 3-4."},
Dish{Name: "Kale Tabbouleh", Description: "A bright, herb-based salad. A perfect starter for vegetarians and vegans."},
Dish{Name: "Garlic Butter Trout", Description: "Baked trout seasoned with garlic, lemon, dill, and, of course, butter. Serves 2."},
}
result, err := coll.InsertMany(context.TODO(), docs)

每个文档都包含某餐厅菜单上菜品的 name(名称)和 description(描述)。

提示

不存在的数据库和集合

如果执行写操作时不存在必要的数据库和集合,服务器会隐式创建这些数据库和集合。

您必须先创建文本索引,再执行文本搜索。文本索引指定要执行文本搜索的字符串或字符串数组字段。

以下部分中的示例对 menu(菜单)集合中的文档的 description(说明)字段执行文本搜索。要启用对 description(说明)字段进行的文本搜索,请使用如下代码段创建一个文本索引:

model := mongo.IndexModel{Keys: bson.D{{"description", "text"}}}
name, err := coll.Indexes().CreateOne(context.TODO(), model)
if err != nil {
panic(err)
}
fmt.Println("Name of index created: " + name)

文本搜索功能将检索文本索引字段中包含术语短语的文档。术语是不包含空格字符的一系列字符。短语是包含任意数量的空白字符的一系列术语。

要执行文本搜索,请使用 $text 评估查询运算符,然后在查询过滤器中使用 $search 字段。$text 操作符对文本索引字段执行文本搜索。$search 字段指定要在文本索引字段中搜索的文本。

文本搜索的查询筛选器使用以下格式:

filter := bson.D{{"$text", bson.D{{"$search", "<text to search>"}}}}

要搜索一个术语,请在查询筛选器中将此术语指定为一个字符串。要搜索多个术语,请在字符串中使用空格分隔每个术语。

注意

搜索多个术语时,Find() 方法会返回文本索引字段中至少包含其中一个术语的文档。

以下示例会对包含术语“herb”(药草)的描述运行文本搜索:

filter := bson.D{{"$text", bson.D{{"$search", "herb"}}}}
cursor, err := coll.Find(context.TODO(), filter)
if err != nil {
panic(err)
}
var results []Dish
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
for _, result := range results {
res, _ := bson.MarshalExtJSON(result, false, false)
fmt.Println(string(res))
}

提示

尽管搜索词是“herb”,但该方法也会匹配包含“herbs”的描述,因为 MongoDB 文本索引使用后缀词干来匹配相似单词。要了解有关 MongoDB 如何匹配术语的更多信息,请参阅索引项。

要搜索短语,请在查询筛选器中将带有转义引号的短语指定为字符串。如果不在短语两边添加转义引号, Find()方法将运行术语搜索。

提示

转义引号是后跟双引号的反斜杠字符。

以下示例对包含短语“serves 2”的描述进行文本搜索:

filter := bson.D{{"$text", bson.D{{"$search", "\"serves 2\""}}}}
cursor, err := coll.Find(context.TODO(), filter)
if err != nil {
panic(err)
}
var results []Dish
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
for _, result := range results {
res, _ := bson.MarshalExtJSON(result, false, false)
fmt.Println(string(res))
}

对于要从文本搜索中排除的每个术语或短语,请在查询筛选器中指定以减号为前缀的术语或短语作为字符串。

重要

如果您要从搜索中排除术语,则必须至少搜索一个术语。如果您不搜索任何术语,则 Find() 方法不会返回任何文档。

以下示例对包含“vegan”但不包含“tofu”的描述进行文本搜索:

filter := bson.D{{"$text", bson.D{{"$search", "vegan -tofu"}}}}
cursor, err := coll.Find(context.TODO(), filter)
if err != nil {
panic(err)
}
var results []Dish
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
for _, result := range results {
res, _ := bson.MarshalExtJSON(result, false, false)
fmt.Println(string(res))
}

文本搜索功能将分配一个数字文本分数,以表明每个结果与查询筛选器中的字符串的匹配程度。要在输出中显示文本分数,请使用一个投影检索 textScore 元数据。您可以指定对 textScore 元数据进行排序,以便按降序顺序对文本分数进行排序。

以下示例执行以下动作:

  • 对包含术语“vegetarian”(素食)的描述进行文本搜索

  • 按结果的文本分数的降序顺序对结果进行排序

  • 仅包括最终输出文档中的 name(名称)和 score(分数)字段

filter := bson.D{{"$text", bson.D{{"$search", "vegetarian"}}}}
sort := bson.D{{"score", bson.D{{"$meta", "textScore"}}}}
projection := bson.D{{"name", 1}, {"score", bson.D{{"$meta", "textScore"}}}, {"_id", 0}}
opts := options.Find().SetSort(sort).SetProjection(projection)
cursor, err := coll.Find(context.TODO(), filter, opts)
if err != nil {
panic(err)
}
var results []bson.D
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
for _, result := range results {
res, _ := bson.MarshalExtJSON(result, false, false)
fmt.Println(string(res))
}

您还可以在$match阶段包含$text评估查询运算符,以在聚合管道中执行文本搜索。

以下示例会对包含术语“herb”(药草)的描述运行文本搜索:

matchStage := bson.D{{"$match", bson.D{{"$text", bson.D{{"$search", "herb"}}}}}}
cursor, err := coll.Aggregate(context.TODO(), mongo.Pipeline{matchStage})
if err != nil {
panic(err)
}
var results []Dish
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
for _, result := range results {
res, _ := bson.MarshalExtJSON(result, false, false)
fmt.Println(string(res))
}

以下示例执行以下动作:

  • 对包含术语“vegetarian”(素食)的描述进行文本搜索

  • 按结果的文本分数的降序顺序对结果进行排序

  • 仅包括最终输出文档中的 name(名称)和 score(分数)字段

matchStage := bson.D{{"$match", bson.D{{"$text", bson.D{{"$search", "vegetarian"}}}}}}
sortStage := bson.D{{"$sort", bson.D{{"score", bson.D{{ "$meta", "textScore" }}}}}}
projectStage := bson.D{{"$project", bson.D{{"name", 1}, {"score", bson.D{{ "$meta", "textScore" }}}, {"_id", 0}}}}
cursor, err := coll.Aggregate(context.TODO(), mongo.Pipeline{matchStage, sortStage, projectStage})
if err != nil {
panic(err)
}
var results []bson.D
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
for _, result := range results {
res, _ := bson.MarshalExtJSON(result, false, false)
fmt.Println(string(res))
}

要了解有关提到的操作的更多信息,请参阅以下指南:

要进一步了解本指南所讨论的任何方法或类型,请参阅以下 API 文档:

← 指定要返回的字段