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