Elasticsearch Operations

Spring Data Elasticsearch 使用多个接口来定义可以针对 Elasticsearch 索引调用的操作 (有关响应式接口的说明,请参阅 Reactive Elasticsearch Operations)。

  • IndexOperations 定义在索引级别上的操作,例如创建或删除索引。

  • DocumentOperations 定义操作来基于其 ID 存储、更新和检索实体。

  • SearchOperations 定义操作以使用查询搜索多个实体

  • ElasticsearchOperations 合并 DocumentOperationsSearchOperations 接口。

这些接口与 Elasticsearch API的结构相对应。 这些接口的默认实现提供了:

  • index management functionality.

  • 针对域类型提供读/写映射支持。

  • 丰富的查询和条件 API。

  • 资源管理和异常转换。

Index management and automatic creation of indices and mappings.

IndexOperations`接口和从 `ElasticsearchOperations`实例可以获取的提供的实现(例如,通过调用 `operations.indexOps(clazz))使用户能够创建索引、放置映射或将模板和别名信息存储在 Elasticsearch 集群中。可以使用 @Setting`注解设置要创建的索引的详细信息,有关更多信息,请参阅 Index settings。 `IndexOperationsElasticsearchOperations 的实现 不会自动执行任何这些操作。调用方法是用户的责任。 支持使用 Spring Data Elasticsearch 存储库时自动创建索引和编写映射,请参见 Automatic creation of indices with the corresponding mapping

Usage examples

该示例展示了如何在 Spring REST 控制器中使用注入的 ElasticsearchOperations`实例。该示例假设 `Person`是使用 `@Document、`@Id`等进行注释的类(请参见 Mapping Annotation Overview)。

Example 1. ElasticsearchOperations usage
@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 文档。

Search Result Types

当使用 DocumentOperations 接口的方法检索文档时,将仅返回发现的实体。使用 SearchOperations 接口的方法搜索时,每个实体都有更多信息,例如发现的实体的 得分排序值

为了返回此信息,每个实体被封装在一个 SearchHit 对象中,该对象包含此实体特定的其他信息。这些 SearchHit 对象本身在 SearchHits 对象中返回,该对象还包含关于整个搜索的信息,比如 maxScore 或请求的聚合。以下类和接口现在可用:

SearchHit<T>

包含以下信息:

  • Id

  • Score

  • Sort Values

  • Highlight fields

  • 内部结果(这是一个嵌入的 SearchHits 对象,可能包含返回的内部 hits)

  • 类型为 <T> 的检索实体

SearchHits<T>

包含以下信息:

  • Number of total hits

  • Total hits relation

  • Maximum score

  • 一堆 SearchHit&lt;T&gt; 对象

  • Returned aggregations

  • Returned suggest results

SearchPage<T>

定义一个包含 SearchHits<T> 元素的 Spring Data Page,可用于在存储库方法中对分页进行访问。

SearchScrollHits<T>

ElasticsearchRestTemplate 中低级滚动 API 函数返回,它使用 Elasticsearch 滚动 ID 丰富 SearchHits<T>

SearchHitsIterator<T>

SearchOperations 接口的流功能返回的迭代器。

ReactiveSearchHits

ReactiveSearchOperations 具有返回 Mono<ReactiveSearchHits<T>> 的方法,其中包含与 SearchHits<T> 对象相同的信息,但会提供包含的 SearchHit<T> 对象,作为 Flux<SearchHit<T>> 而不是列表。

Queries

SearchOperationsReactiveSearchOperations 接口中定义的几乎所有方法都会采用一个 Query 参数,该参数定义用于执行搜索的查询。Query 是一个接口,Spring Data Elasticsearch 提供三种实现:CriteriaQueryStringQueryNativeQuery

CriteriaQuery

基于 CriteriaQuery 的查询允许创建查询以搜索数据而不了解 Elasticsearch 查询的语法或基础知识。它们允许用户通过简单地链接和组合指定被搜索文档必须满足的条件的 Criteria 对象来构建查询。

在讨论组合标准时的 AND 或 OR 时,请记住,在 Elasticsearch 中 AND 转换为 must 条件,而 OR 转换为 should

Criteria 及其用法可以通过示例得到最好的解释(让我们假设我们有一个具有 price 属性的 Book 实体):

Example 2. Get books with a given price
Criteria criteria = new Criteria("price").is(42.0);
Query query = new CriteriaQuery(criteria);

同一字段的条件可以链接,它们将与逻辑 AND 结合:

Example 3. Get books with a given price
Criteria criteria = new Criteria("price").greaterThan(42.0).lessThan(34.0);
Query query = new CriteriaQuery(criteria);

在链接 Criteria 时,默认情况下使用 AND 逻辑:

Example 4. Get all persons with first name James and last name Miller:
Criteria criteria = new Criteria("lastname").is("Miller") 1
  .and("firstname").is("James")                           2
Query query = new CriteriaQuery(criteria);
1 the first Criteria
2 and() 创建一个新的 Criteria 并将其连接到第一个。

如果你想要创建嵌套查询,你需要为此使用子查询。让我们假设我们要找到姓氏为 Miller,名要么为 JackJohn 的所有人员:

Example 5. Nested subqueries
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 组合成一个子条件
3 此子条件是一个 OR 组合,用于名 John
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 的人员,并让找到的文档具有一个术语聚合,该术语聚合会统计这些人员的 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`接口的特殊实现,与存储的搜索模板结合使用。有关详细信息,请参见 Search Template support