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 对象中,该对象还包含有关整个搜索的信息,例如 maxScore、请求的聚合或完成请求所需的执行持续时间。
现在可以使用以下类和接口:
包含以下信息:
-
Id
-
分数
-
排序值
-
高亮字段
-
内部命中(这是一个嵌入的
SearchHits对象,最终包含返回的内部命中结果) -
检索到的类型为 <T> 的实体
包含以下信息:
-
总命中数
-
总命中关系
-
最高分数
-
一个包含
SearchHit<T>个对象的列表 -
返回的聚合结果
-
返回的建议结果
定义了一个包含 SearchHits<T> 元素的 Spring Data Page,可用于通过仓库方法进行分页访问。
由底层滚动 API 函数在 ElasticsearchRestTemplate 中返回,它使用 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 组合 |
| 3 | 此子条件是名字 John 的“或”组合条件。 |
| 4 | 且名字为 Jack |
请参阅 Criteria 类的 API 文档,以获取所有可用操作的完整概述。
字符串查询
此类将 Elasticsearch 查询作为 JSON 字符串接收。 以下代码展示了一个搜索名字为“Jack”的人员的查询:
Query query = new StringQuery("{ \"match\": { \"firstname\": { \"query\": \"Jack\" } } } ");
SearchHits<Person> searchHits = operations.search(query, Person.class);
如果您已经有一个要使用的 Elasticsearch 查询,使用 StringQuery 可能是合适的。
原生查询
NativeQuery 是当您拥有复杂查询,或无法通过 Criteria API 表达的查询(例如构建查询和使用聚合时)应使用的类。
它允许使用 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);
搜索模板查询
这是 Query 接口的一个特殊实现,需与存储的搜索模板结合使用。
请参阅 搜索模板支持 以获取更多信息。