Elasticsearch 操作
Spring Data Elasticsearch 使用若干接口来定义可针对 Elasticsearch 索引调用的操作(响应式接口的说明请参阅响应式 Elasticsearch 操作)。
-
IndexOperations 定义索引层面的操作,如创建或删除索引。
-
DocumentOperations 定义根据 id 存储、更新和检索实体的操作。
-
SearchOperations 定义使用查询搜索多个实体的操作。
-
ElasticsearchOperations 组合了
DocumentOperations和SearchOperations接口。
这些接口与 Elasticsearch API的结构相对应。
这些接口的默认实现提供:
-
索引管理功能。
-
领域类型的映射读写支持。
-
丰富的查询和条件 API。
-
资源管理和异常转换。
索引管理以及索引和映射的自动创建。
IndexOperations 接口以及可从 ElasticsearchOperations 实例获取的实现——例如通过调用 operations.indexOps(clazz)——让用户能够创建索引、放入映射,或将模板和别名信息存储到 Elasticsearch 集群中。将要创建的索引的详细信息可以通过 @Setting 注解设置,更多信息请参阅索引设置。
IndexOperations 或 ElasticsearchOperations 的实现不会自动完成这些操作中的任何一项。调用这些方法是用户的责任。
使用 Spring Data Elasticsearch 仓库时支持自动创建索引和写入映射,请参阅自动创建索引及相应映射
用法示例
此示例展示如何在 Spring REST 控制器中使用注入的 ElasticsearchOperations 实例。示例假设 Person 是一个用 @Document、@Id 等注解标注的类(请参阅映射注解概览)。
示例 1. ElasticsearchOperations 用法
@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;
}
}
让 Spring 在构造函数中注入所提供的
ElasticsearchOperationsBean。将某个实体存储到 Elasticsearch 集群中。id 从返回的实体中读取,因为它在
person对象中可能为 null,而由 Elasticsearch 创建。通过按 id 获取来检索实体。
要了解 ElasticsearchOperations 的全部功能,请参阅 API 文档。
搜索结果类型
当使用 DocumentOperations 接口的方法检索文档时,只会返回找到的实体。当使用 SearchOperations 接口的方法进行搜索时,每个实体都有额外信息可用,例如找到实体的 score 或 sortValues。
为了返回这些信息,每个实体都被包装在一个 SearchHit 对象中,该对象包含此实体特有的额外信息。这些 SearchHit 对象本身又在一个 SearchHits 对象中返回,后者还包含关于整个搜索的信息,如 maxScore、请求的聚合,或完成请求所花费的执行时长。现在有以下类和接口可用:
SearchHit<T>
包含以下信息:
-
Id
-
评分
-
排序值
-
高亮字段
-
Inner hits(这是一个内嵌的
SearchHits对象,包含最终返回的 inner hits) -
类型为 <T> 的检索到的实体
SearchHits<T>
包含以下信息:
-
总命中数
-
总命中关系
-
最大评分
-
SearchHit<T>对象的列表 -
返回的聚合
-
返回的补全建议结果
SearchPage<T>
定义一个 Spring Data Page,其中包含一个 SearchHits<T> 元素,可用于通过仓库方法进行分页访问。
SearchScrollHits<T>
由 ElasticsearchRestTemplate 中的低级 scroll API 函数返回,它用 Elasticsearch scroll id 丰富了 SearchHits<T>。
SearchHitsIterator<T>
由 SearchOperations 接口的流式函数返回的一个 Iterator。
ReactiveSearchHits
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 实体):
示例 2. 获取具有给定价格的书籍
Criteria criteria = new Criteria("price").is(42.0);
Query query = new CriteriaQuery(criteria);
同一字段的条件可以链式调用,它们将以逻辑 AND 组合:
示例 3. 获取具有给定价格的书籍
Criteria criteria = new Criteria("price").greaterThan(42.0).lessThan(34.0);
Query query = new CriteriaQuery(criteria);
链式调用 Criteria 时,默认使用 AND 逻辑:
示例 4. 获取所有名字为 James、姓氏为 Miller 的人员:
Criteria criteria = new Criteria("lastname").is("Miller") 1
.and("firstname").is("James") 2
Query query = new CriteriaQuery(criteria);
第一个
Criteriaand() 创建一个新的
Criteria并将其链接到第一个。
如果您想创建嵌套查询,需要为此使用子查询。假设我们想查找所有姓氏为 Miller、且名字为 Jack 或 John 的人员:
示例 5. 嵌套子查询
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);
为姓氏创建第一个
Criteria这以 AND 组合为一个 subCriteria
此子条件是对名字 John 的 OR 组合
以及名字 Jack
有关各种可用操作的完整概览,请参阅 Criteria 类的 API 文档。
StringQuery
此类接收一个 JSON 字符串形式的 Elasticsearch 查询。以下代码展示了一个查询,用于搜索名字为 "Jack" 的人员:
Query query = new StringQuery("{ \"match\": { \"firstname\": { \"query\": \"Jack\" } } } ");
SearchHits<Person> searchHits = operations.search(query, Person.class);
如果您已经有一个要使用的 Elasticsearch 查询,使用 StringQuery 可能是合适的。
NativeQuery
NativeQuery 是在您有复杂查询、或无法使用 Criteria API 表达的查询时使用的类,例如在构建查询并使用聚合时。它允许使用来自 Elasticsearch 库的各种 co.elastic.clients.elasticsearch._types.query_dsl.Query 实现,因此被命名为 "native"(原生)。
以下代码展示如何搜索具有给定 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 接口的一个特殊实现,与存储的搜索模板结合使用。更多信息请参阅搜索模板支持。