搜索文本
概述
在本指南中,您可以了解如何使用 Rust 驱动程序运行文本搜索。文本搜索允许您高效地查询具有字符串值的字段。
重要
MongoDB 文本搜索与更强大的 Atlas Search 功能不同。要了解更多信息,请参阅Atlas Search 文档.
本指南包括以下部分
示例用例的数据样本
本指南中的示例使用以下内容Dish
结构作为 menu
集合中文档的模型
struct Dish { name: String, description: String, }
以下示例使用了以下样本文档,描述了您可以在餐厅订餐的菜品
{ "name": "Shepherd’s Pie", "description": "A vegetarian take on the classic dish that uses lentils as a base. Serves 2." }, { "name": "Green Curry", "description": "A flavorful Thai curry, made vegetarian with tofu. Vegetarian and vegan friendly." }, { "name": "Herbed Branzino", "description": "Grilled whole fish stuffed with herbs and pomegranate seeds. Serves 3-4." }, { "name": "Kale Tabbouleh", "description": "A bright, herb-based salad. A perfect starter for vegetarians and vegans." }, { "name": "Garlic Butter Trout", "description": "Baked trout seasoned with garlic, lemon, dill, and, of course, butter. Serves 2." }
文本索引
在执行文本搜索之前,您必须在集合上创建一个 文本索引。文本索引指定可以执行文本搜索的字符串或字符串数组字段。
本指南中的示例在 menu
集合中文档的 description
字段上执行文本搜索。要启用 description
字段的文本搜索,请创建如下代码所示的文本索引
let index = IndexModel::builder() .keys(doc! { "description": "text" }) .build(); let idx_res = my_coll.create_index(index).await?;
文本搜索
文本搜索检索包含指定 术语 或 短语 的索引字段值的文档。术语是一系列不包括空白字符的字符。短语是一系列可以包含任意数量空白字符的术语。
要执行文本搜索,请将 $text
评估查询运算符包含在查询过滤器中,后跟 $search
字段。$text
运算符指定您正在对文本索引字段执行文本搜索。$search
字段指定在文本索引字段或字段中搜索的术语或短语。
文本搜索的查询过滤器使用以下格式
let filter = doc! { "$text": { "$search": "<search term or phrase>" } };
搜索一个术语
要搜索一个术语,请在查询过滤器中将术语指定为字符串。要搜索多个术语,请用空格分隔每个术语。
注意
当搜索多个术语时,find()
方法返回任何包含至少一个术语的文本索引字段或字段的文档。
例如,如果您的搜索术语是"one two three"
,MongoDB将返回包含索引字段包含"one"
、"two"
、"three"
或这些术语中多个术语的文档。
示例
以下示例演示了在包含术语"herb"
的description
字段中搜索文档。
let filter = doc! { "$text": { "$search": "herb" } }; let mut cursor = my_coll.find(filter).await?; while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Dish { name: "Kale Tabbouleh", description: "A bright, herb-based salad. A perfect starter for vegetarians and vegans." } Dish { name: "Herbed Branzino", description: "Grilled whole fish stuffed with herbs and pomegranate seeds. Serves 3-4." }
提示
即使搜索术语是"herb"
,文本搜索也会匹配包含"herbs"
的description
字段的文档。这是因为MongoDB文本索引使用后缀词干提取来匹配类似词语。有关MongoDB如何匹配术语的更多信息,请参阅服务器手册中的索引条目。
搜索短语
要搜索短语,请在查询过滤器中使用转义引号指定短语
let filter = doc! { "$text": { "$search": "\"<some phrase>\"" } };
如果您没有在短语周围添加转义引号,则搜索将执行词搜索。
示例
以下示例搜索包含短语 "serves 2"
的文档
let filter = doc! { "$text": { "$search": "\"serves 2\"" } }; let mut cursor = my_coll.find(filter).await?; while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Dish { name: "Shepherd’s Pie", description: "A vegetarian take on the classic dish that uses lentils as a base. Serves 2." } Dish { name: "Garlic Butter Trout", description: "Baked trout seasoned with garlic, lemon, dill, and, of course, butter. Serves 2." }
从搜索中排除术语
要指定您希望从文本搜索中排除的术语或短语,请在查询过滤器中使用减号作为前缀
let filter = doc! { "$text": { "$search": "<term> -<excluded term>" } };
重要
您必须搜索至少一个术语或短语,才能从搜索中排除其他术语。如果您只排除术语,则搜索不会返回任何文档。
示例
以下示例在描述字段包含术语“vegan”但不含术语“tofu”的文档中进行搜索
let filter = doc! { "$text": { "$search": "vegan -tofu" } }; let mut cursor = my_coll.find(filter).await?; while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Dish { name: "Kale Tabbouleh", description: "A bright, herb-based salad. A perfect starter for vegetarians and vegans." }
按相关性排序
文本搜索会分配一个数值文本得分来指示每个结果与您的查询过滤器中的字符串的匹配程度。得分越高,表示结果与您的查询越相关。要在输出中显示文本得分,请使用投影检索元数据中的textScore
字段。您可以通过指定对textScore
元数据字段的排序来按降序排序文本得分。
示例
此示例执行以下操作
在描述字段包含术语“vegetarian”的文档中进行搜索
按文本得分降序排序结果
输出中仅包含
名称
和分数
字段。
let filter = doc! { "$text": { "$search": "vegetarian" } }; let sort = doc! { "score": { "$meta": "textScore" } }; let projection = doc! { "_id": 0, "name": 1, "score": { "$meta": "textScore" } }; let doc_coll: Collection<Document> = my_coll.clone_with_type(); let mut cursor = doc_coll.find(filter) .sort(sort) .projection(projection) .await?; while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Document({"name": String("Green Curry"), "score": Double(0.9166666666666667)}) Document({"name": String("Kale Tabbouleh"), "score": Double(0.5625)}) Document({"name": String("Shepherd’s Pie"), "score": Double(0.5555555555555556)})
聚合
您可以将 $text
评估查询操作符包含在 $match 聚合阶段中,以在聚合管道中执行文本搜索。
以下部分展示了如何通过使用聚合管道而不是 find()
方法来执行文本搜索。
匹配搜索词
以下示例使用聚合来搜索包含 描述
字段中包含术语 "herb"
的文档。
let match_stage = doc! { "$match": { "$text": { "$search": "herb" } } }; let mut cursor = my_coll.aggregate([match_stage]).await?; while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Document({"_id": ObjectId("..."), "name": String("Kale Tabbouleh"), "description": String("A bright, herb-based salad. A perfect starter for vegetarians and vegans.")}) Document({"_id": ObjectId("..."), "name": String("Herbed Branzino"), "description": String("Grilled whole fish stuffed with herbs and pomegranate seeds. Serves 3-4.")})
按相关性排序
此示例使用聚合执行以下操作
在描述字段包含术语“vegetarian”的文档中进行搜索
按文本得分降序排序结果
输出中仅包含
名称
和分数
字段。
let match_stage = doc! { "$match": { "$text": { "$search": "vegetarian" } } }; let sort_stage = doc! { "$sort": { "score": { "$meta": "textScore" } } }; let proj_stage = doc! { "$project": { "_id": 0, "name": 1, "score": { "$meta": "textScore" } } }; let pipeline = [match_stage, sort_stage, proj_stage]; let mut cursor = my_coll.aggregate(pipeline).await?; while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Document({"name": String("Green Curry"), "score": Double(0.9166666666666667)}) Document({"name": String("Kale Tabbouleh"), "score": Double(0.5625)}) Document({"name": String("Shepherd’s Pie"), "score": Double(0.5555555555555556)})
附加信息
有关使用 find()
方法的可运行示例,请参阅查找多个文档 用例。
要了解更多关于本指南中所述的操作的信息,请参阅以下文档
API 文档
要了解本指南中提到的方法和类型,请参阅以下 API 文档