Elasticsearch 操作
Spring Data Elasticsearch 使用多个接口来定义可以针对 Elasticsearch 索引调用的操作(有关响应式接口的描述,请参见 响应式 Elasticsearch 操作)。
-
IndexOperations定义了索引级别的操作,例如创建或删除索引。 -
DocumentOperations定义了根据实体 ID 存储、更新和检索实体的操作。 -
SearchOperations定义了使用查询搜索多个实体的操作。 -
ElasticsearchOperations结合了DocumentOperations和SearchOperations接口。
这些接口与 Elasticsearch API 的结构相对应。
这些接口的默认实现提供
-
索引管理功能。
-
领域类型的读/写映射支持。
-
丰富的查询和条件 API。
-
资源管理和异常转换。
|
索引管理以及索引和映射的自动创建。
这些操作都不会由 使用 Spring Data Elasticsearch 仓库时,支持自动创建索引和写入映射,请参见 自动创建带有相应映射的索引 |
使用示例
此示例展示了如何在 Spring REST 控制器中使用注入的 ElasticsearchOperations 实例。示例假设 Person 是一个用 @Document、@Id 等注解的类(请参见 映射注解概述)。
@RestController
@RequestMapping("/")
public class TestController {
private ElasticsearchOperations elasticsearchOperations;
public TestController(ElasticsearchOperations elasticsearchOperations) { (1)
this.elasticsearchOperations = elasticsearchOperations;
}
@PostMapping("/person")
public String save(@RequestBody Person person) { (2)
Person savedEntity = elasticsearchOperations.save(person);
return savedEntity.getId();
}
@GetMapping("/person/{id}")
public Person findById(@PathVariable("id") Long id) { (3)
Person person = elasticsearchOperations.get(id.toString(), Person.class);
return person;
}
}
| 1 | 让 Spring 在构造函数中注入提供的 ElasticsearchOperations bean。 |
| 2 | 在 Elasticsearch 集群中存储一些实体。ID 从返回的实体中读取,因为它可能在 person 对象中为 null 并由 Elasticsearch 创建。 |
| 3 | 通过 ID 获取实体。 |
要查看 ElasticsearchOperations 的所有可能性,请参阅 API 文档。
搜索结果类型
当使用 DocumentOperations 接口的方法检索文档时,只返回找到的实体。当使用 SearchOperations 接口的方法进行搜索时,每个实体都有额外的信息可用,例如找到的实体的分数(score)或排序值(sortValues)。
为了返回这些信息,每个实体都被包装在一个 SearchHit 对象中,该对象包含这些实体特定的附加信息。这些 SearchHit 对象本身又在 SearchHits 对象中返回,SearchHits 对象还包含有关整个搜索的信息,例如最大分数(maxScore)或请求的聚合或完成请求所花费的执行时间。以下类和接口现已可用:
包含以下信息
-
ID
-
分数(Score)
-
排序值(Sort Values)
-
高亮字段
-
内部命中(这是一个嵌入的
SearchHits对象,包含最终返回的内部命中) -
检索到的类型为 <T> 的实体
包含以下信息
-
总命中数
-
总命中关系
-
最大分数(Maximum score)
-
一个
SearchHit<T>对象列表 -
返回的聚合
-
返回的建议结果
定义了一个 Spring Data Page,其中包含一个 SearchHits<T> 元素,可用于使用仓库方法进行分页访问。
由 ElasticsearchRestTemplate 中的低级滚动 API 函数返回,它使用 Elasticsearch 滚动 ID 丰富了 SearchHits<T>。
由 SearchOperations 接口的流式函数返回的迭代器。
ReactiveSearchOperations 的方法返回 Mono<ReactiveSearchHits<T>>,它包含与 SearchHits<T> 对象相同的信息,但会将包含的 SearchHit<T> 对象作为 Flux<SearchHit<T>> 而非列表提供。
查询
SearchOperations 和 ReactiveSearchOperations 接口中定义的所有方法几乎都接受一个 Query 参数,该参数定义要执行的搜索查询。Query 是一个接口,Spring Data Elasticsearch 提供了三个实现:CriteriaQuery、StringQuery 和 NativeQuery。
CriteriaQuery
基于 CriteriaQuery 的查询允许创建用于搜索数据的查询,而无需了解 Elasticsearch 查询的语法或基础知识。它们允许用户通过简单地链接和组合指定搜索文档必须满足的条件的 Criteria 对象来构建查询。
| 当谈到组合条件时的 AND 或 OR 时,请记住,在 Elasticsearch 中,AND 被转换为 **must** 条件,OR 被转换为 **should** 条件。 |
Criteria 及其用法最好通过示例解释(假设我们有一个带有 price 属性的 Book 实体)
Criteria criteria = new Criteria("price").is(42.0);
Query query = new CriteriaQuery(criteria);
同一字段的条件可以链接,它们将与逻辑 AND 组合
Criteria criteria = new Criteria("price").greaterThan(42.0).lessThan(34.0);
Query query = new CriteriaQuery(criteria);
链接 Criteria 时,默认使用 AND 逻辑
Criteria criteria = new Criteria("lastname").is("Miller") (1)
.and("firstname").is("James") (2)
Query query = new CriteriaQuery(criteria);
| 1 | 第一个 Criteria |
| 2 | and() 创建一个新的 Criteria 并将其链接到第一个。 |
如果您想创建嵌套查询,则需要为此使用子查询。假设我们想查找所有姓氏为 Miller 且名字为 Jack 或 John 的人
Criteria miller = new Criteria("lastName").is("Miller") (1)
.subCriteria( (2)
new Criteria().or("firstName").is("John") (3)
.or("firstName").is("Jack") (4)
);
Query query = new CriteriaQuery(criteria);
| 1 | 为姓氏创建一个第一个 Criteria |
| 2 | 这与 AND 组合成一个子 Criteria |
| 3 | 这个子 Criteria 是名字为 John 的 OR 组合 |
| 4 | 以及名字为 Jack |
有关可用操作的完整概述,请参阅 Criteria 类的 API 文档。
StringQuery
此类将 Elasticsearch 查询作为 JSON 字符串。以下代码显示了一个搜索名字为 "Jack" 的人的查询
Query query = new StringQuery("{ \"match\": { \"firstname\": { \"query\": \"Jack\" } } } ");
SearchHits<Person> searchHits = operations.search(query, Person.class);
如果您已经有一个可用的 Elasticsearch 查询,使用 StringQuery 可能是合适的。
NativeQuery
当您有一个复杂查询,或者一个无法通过使用 Criteria API 表达的查询(例如在构建查询和使用聚合时),NativeQuery 是要使用的类。它允许使用 Elasticsearch 库中所有不同的 co.elastic.clients.elasticsearch._types.query_dsl.Query 实现,因此被称为“原生”。
以下代码展示了如何搜索具有给定 firstName 的人,并为找到的文档进行 terms 聚合,以计算这些人的 lastName 出现次数
Query query = NativeQuery.builder()
.withAggregation("lastNames", Aggregation.of(a -> a
.terms(ta -> ta.field("lastName").size(10))))
.withQuery(q -> q
.match(m -> m
.field("firstName")
.query(firstName)
)
)
.withPageable(pageable)
.build();
SearchHits<Person> searchHits = operations.search(query, Person.class);
SearchTemplateQuery
这是 Query 接口的一种特殊实现,与存储的搜索模板结合使用。有关更多信息,请参见 搜索模板支持。