从 MongoDB 2.6 版开始,您可以使用 $text 运算符运行全文查询。TextQuery 和 TextCriteria 中提供了特定于全文查询的方法和操作。
在实际使用全文搜索之前,必须正确设置搜索索引。有关如何创建索引结构的详细信息,请参阅文本索引。以下示例显示了如何设置全文搜索:
db.foo.createIndex({ title : "text", content : "text" }, { weights : { title : 3 } })
可以像下面一样定义和运行搜索 “咖啡蛋糕” 的查询:
Query query = TextQuery .queryText(new TextCriteria().matchingAny("coffee", "cake")); List<Document> page = template.find(query, Document.class);
要根据权重按相关性排序结果,请使用 TextQuery.sortByScore():
Query query = TextQuery .queryText(new TextCriteria().matchingAny("coffee", "cake")) // (1) 使用 score 属性按相关性对结果进行排序,这会触发.sort({'score': {'$meta': 'textScore'}}) .sortByScore() // (2) 使用TextQuery.includeScore()将计算出的相关度包括在结果的 Document 中 .includeScore(); List<Document> page = template.find(query, Document.class);
你可以通过在搜索词前加上 “-” 或者使用 notMatching 来排除搜索词,如下例所示(注意,这两行有相同的效果,因此是多余的):
// 搜索 “coffee” 而不是 “cake” TextQuery.queryText(new TextCriteria().matching("coffee").matching("-cake")); TextQuery.queryText(new TextCriteria().matching("coffee").notMatching("cake"));
TextCriteria.matching() 按原样使用提供的术语。。因此,你可以通过把短语放在双引号之间(例如,\"coffee cake\")或使用 TextCriteria.phrase 来定义短语。下面的例子显示了定义短语的两种方式:
// 搜索短语 'coffee cake' TextQuery.queryText(new TextCriteria().matching("\"coffee cake\"")); TextQuery.queryText(new TextCriteria().phrase("coffee cake"));
注意:你可以通过使用 TextCriteria 上的相应方法为 $caseSensitive 和 $diacriticSensitive 设置标志。请注意,这两个可选的标志在 MongoDB 3.2 中被引入,除非明确设置,否则不包括在查询中。
(1)创建 Book 实体,代码如下:
package com.hxstrive.springdata.mongodb.entity; import lombok.Builder; import lombok.Data; import lombok.ToString; @Data @Builder @ToString public class Book { /** 书籍ID */ private int id; /** 书籍名称 */ private String name; /** 书籍价格 */ private float price; /** 书籍描述信息 */ private String summary; }
(2)客户端代码,演示怎样使用全文索引,代码如下:
package com.hxstrive.springdata.mongodb.query; import com.hxstrive.springdata.mongodb.entity.Book; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.index.IndexDefinition; import org.springframework.data.mongodb.core.index.TextIndexDefinition; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.TextCriteria; import org.springframework.data.mongodb.core.query.TextQuery; import java.util.List; @SpringBootTest public class FullTextQueryTest { @Autowired private MongoTemplate mongoTemplate; @BeforeEach public void init() { // 删除集合,清空数据 mongoTemplate.dropCollection(Book.class); // 准备数据 mongoTemplate.insert(Book.builder().id(100).name("NoSQL数据库实战派:Redis + MongoDB + HBase") .price(118.0f) .summary("本书介绍了 NoSQL 数据库生态圈体系,包括 Redis、MongoDB 和 HBase,内容涉及开发、运维、管理与架构。") .build()); mongoTemplate.insert(Book.builder().id(200).name("MongoDB 权威指南 第3版") .price(108.7f) .summary("本书是由 MongoDB 团队成员撰写的入门指南,涵盖从开发到部署的各个方面,内容适合MongoDB 4.2及以上版本。") .build()); mongoTemplate.insert(Book.builder().id(300).name("MongoDB 进阶与实战:微服务整合、性能优化、架构管理") .price(118.0f) .summary("本书围绕如何用好MongoDB这个复杂命题,利用大部分篇幅讲述了MongoDB在应用开发方面的各种进阶技巧," + "同时也介绍了MongoDB 4.0版本的事务特性及微服务相关的技术范例。") .build()); // 进行全文索引,必须创建索引 // 下面在 summary 字段上面创建索引 mongoTemplate.indexOps(Book.class).ensureIndex( TextIndexDefinition.builder().onField("summary").build()); } @Test public void contextLoads() { // 查询 summary 字段中包含 MongoDB 单词的记录 Query query = TextQuery.queryText(new TextCriteria().matchingAny("MongoDB")); List<Book> bookList = mongoTemplate.find(query, Book.class); for(Book book : bookList) { System.out.println(book); } // 根据搜索只输出了 ID 为 100 和 200 的数据,因为它们的 summary 中包含了 MongoDB 单词 // 而 ID 为 300 的记录中有 MongoDB,但是没有使用空格分开,不算单词,也就搜索不到 } @Test public void contextLoads2() { // 查询 summary 字段中包含 MongoDB 或者 HBase 单词的记录 Query query = TextQuery.queryText(new TextCriteria().matchingAny("MongoDB", "HBase")); List<Book> bookList = mongoTemplate.find(query, Book.class); for(Book book : bookList) { System.out.println(book); } } @Test public void contextLoads3() { // 搜索短语 'MongoDB 和 HBase',由多个单词组成 List<Book> bookList = mongoTemplate.find( TextQuery.queryText(new TextCriteria().matching("\"MongoDB 和 HBase\"")), Book.class); for(Book book : bookList) { System.out.println(book); } System.out.println("=================分割线=================="); // 等价 bookList = mongoTemplate.find( TextQuery.queryText(new TextCriteria().matchingPhrase("MongoDB 和 HBase")), Book.class); for(Book book : bookList) { System.out.println(book); } } }