Spring Data Elasticsearch 中 ElasticsearchOperations 构建查询条件的详解
前言
在现代开发中,搜索引擎技术被广泛应用于处理大量数据和实现高效的查询。在这些技术中,Elasticsearch 是一个非常强大的工具,而 Spring Data Elasticsearch 提供了与之进行交互的便利工具。本篇文章将详细介绍如何使用 ElasticsearchOperations 进行常见查询构建操作,重点是通过 Criteria 和 Query 来构建查询条件,并演示如何使用它们进行增、删、改、查等常见操作。
一、引入依赖
首先,我们需要在 pom.xml
中添加相关的依赖,以便能够使用 Spring Data Elasticsearch 提供的功能。
<!-- Elasticsearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
二、配置 Elasticsearch
在应用的 application.yaml
文件中,我们需要配置 Elasticsearch 的连接信息,通常是一个本地或远程的 Elasticsearch 。
spring:
elasticsearch:
uris: 127.0.0.1:9200
username: elastic
password: xxxxxxxxxx
ssl:
verification-mode: none
这个配置将使得 Spring Data Elasticsearch 通过 ElasticsearchOperations 连接到你的 Elasticsearch 。
三、创建模型类(Entity)
在进行 Elasticsearch 操作时,通常需要一个与 Elasticsearch 索引相对应的模型类。我们以 Product 类为例:
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@Document(indexName = "products", createIndex = true) // 指定索引名称,并且会自动创建索引
public class Product {
@Id
private Long id; // Elasticsearch 会自动使用此字段作为文档的唯一标识
@Field(type = FieldType.Text, analyzer = "standard") // 用来指定 Elasticsearch 中字段的数据类型和分词器
private String name;
@Field(type = FieldType.Double) // 指定字段类型为 Double 类型
private Double price;
}
此类将用于与 Elasticsearch 中的 products
索引进行交互。
四、使用 ElasticsearchOperations
进行 CRUD 操作
1. 保存数据(Create)
使用 ElasticsearchOperations
保存数据非常简单。你只需要创建一个 Product
对象并调用 save()
方法。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.junit.jupiter.api.Test;
public class ProductServiceTest {
@Autowired
private ElasticsearchOperations elasticsearchOperations;
@Test
public void testSaveProduct() {
Product product = new Product();
product.setId(1L);
product.setName("手机");
product.setPrice(2999.0);
Product savedProduct = elasticsearchOperations.save(product); // 保存到 Elasticsearch
System.out.println("Saved Product: " + savedProduct);
}
}
这个简单的示例展示了如何通过 ElasticsearchOperations
保存一个 Product
对象。返回的 savedProduct
是保存后的对象,包含了 Elasticsearch 生成的 ID(如果没有指定的话)。
2. 获取数据(Read)
可以通过 get()
方法根据 ID 获取单个文档,或者通过 search()
方法根据查询条件获取多个文档。
获取单个文档:
@Test
public void testGetProductById() {
Product product = elasticsearchOperations.get("1", Product.class); // 通过 ID 获取文档
System.out.println("Retrieved Product: " + product);
}
查询多个文档:
可以通过 Criteria
来构建查询条件,然后使用 search()
方法来查询匹配的文档。
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.domain.PageRequest;
@Test
public void testSearchProductsByName() {
// 构建查询条件
Criteria criteria = new Criteria("name").is("手机");
CriteriaQuery query = new CriteriaQuery(criteria);
query.setPageable(PageRequest.of(0, 10)); // 设置分页
// 执行查询
SearchHits<Product> results = elasticsearchOperations.search(query, Product.class);
results.forEach(hit -> System.out.println("Product: " + hit.getContent()));
}
展示了如何根据商品名称进行查询,并使用分页来限制返回的结果。
3. 更新数据(Update)
通常情况下,save()
方法会在 Elasticsearch 中执行插入或更新操作。如果想更新已有的文档,只需要重新保存即可。例如:
@Test
public void testUpdateProduct() {
Product product = elasticsearchOperations.get("1", Product.class);
product.setPrice(2599.0); // 修改价格
elasticsearchOperations.save(product); // 保存会自动执行更新
}
4. 删除数据(Delete)
删除数据可以通过 delete() 方法来完成,只需要传入文档的 ID。
@Test
public void testDeleteProduct() {
elasticsearchOperations.delete("1", Product.class); // 删除指定 ID 的文档
}
五、构建查询条件:使用 Criteria
和 CriteriaQuery
ElasticsearchOperations
允许我们通过 Criteria
来构建查询条件。Criteria
类可以用来构建多种查询,包括等值查询、范围查询等。你可以通过组合 Criteria
对象来创建复杂的查询。
常见查询条件
等值查询
Criteria criteria = new Criteria("name").is("手机");
范围查询
Criteria criteria = new Criteria("price").between(1000, 5000);
大于查询
Criteria criteria = new Criteria("price").greaterThan(1000);
小于查询
Criteria criteria = new Criteria("price").lessThan(5000);
模糊查询
Criteria criteria = new Criteria("name").contains("平板");
集合成员查询
in(...)
在字段中查找包含在给定集合或数组内的文档。
// 等同于 terms 查询,适用于 Keyword 或不分词字段 Criteria c = new Criteria("status").in("ACTIVE", "PENDING");
notIn(...)
排除指定集合或数组中的值。
// 排除 status 为 ACTIVE 或 PENDING 的文档 Criteria c = new Criteria("status").notIn("ACTIVE", "PENDING");
多条件查询
Criteria criteria1 = new Criteria("name").is("手机"); Criteria criteria2 = new Criteria("price").greaterThan(2000); CriteriaQuery query = new CriteriaQuery(criteria1.and(criteria2)); // AND 查询
分页和排序
分页和排序对于大数据量查询非常重要。可以使用 Pageable 来进行分页设置,使用 Sort 来进行排序。
分页查询
query.setPageable(PageRequest.of(0, 10)); // 获取第1页,每页10条记录
排序查询
query.addSort(Sort.by(Sort.Order.asc("price"))); // 按价格升序排序
复合查询
使用
CriteriaQuery
,你可以将多个查询条件通过and
或or
进行组合:Criteria criteria1 = new Criteria("name").is("手机"); Criteria criteria2 = new Criteria("price").greaterThan(2000); CriteriaQuery query = new CriteriaQuery(criteria1.and(criteria2)); // AND 查询
六、注解配置 Elasticsearch 索引和字段映射
1. @Document
注解
@Document
注解用于指定类对应的 Elasticsearch 索引。在索引的配置中,可以指定索引名称、是否自动创建索引等。
@Document(indexName = "products", createIndex = true) // 指定索引名称,并且会自动创建索引
public class Product {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "standard") // 用来指定 Elasticsearch 中字段的数据类型和分词器
private String name;
@Field(type = FieldType.Double) // 指定字段类型为 Double 类型
private Double price;
}
2. @Id
注解
@Id
注解用于标识文档的唯一标识符字段。这个字段会被作为 Elasticsearch 索引文档的 _id
。
@Id
private String id;
3. @Field
注解
@Field
注解用于指定字段在 Elasticsearch 中的类型、分词器等配置。它支持多种类型,如 Text
、Keyword
、Double
等,并且可以配置分词器(analyzer
)等属性。
@Field(type = FieldType.Text, analyzer = "standard")
private String name;
@Field(type = FieldType.Double)
private Double price;
4. @Setting
注解
还可以使用 @Setting
注解来配置索引的详细设置,如分片数、副本数等。
@Setting(shards = 3, replicas = 2)
@Document(indexName = "products")
public class Product {
// Fields ...
}
总结
ElasticsearchOperations
:适合常见 CRUD 和基础查询(等值、范围、模糊、组合、分页、排序)。Criteria
+CriteriaQuery
:以链式方式构建查询,无需掌握原生 DSL 语法。注解映射:通过
@Document
、@Field
、@Setting
精细控制索引与字段。对于聚合、高亮、异步和大批量操作等高级需求,应使用
ElasticsearchRestTemplate
或直接调用 Elasticsearch Java 客户端。