8. Elasticsearch Repositories
本章包括 Elasticsearch repository实现的细节
8.1.1. Query methods 查询方法
Elasticsearch模块支持所有基本的查询构建特性,如字符串查询、本机搜索查询、基于条件的查询或从方法名派生查询
Declared queryies 声明的查询
从方法名称派生查询并不总是足够的,并且/或者可能导致方法名称不可读。 在这种情况下,可以使用@Query注解(请参阅使用@Query注解 )。
8.1.2 Query creation 查询创建
一般来说,Elasticsearch的查询创建机制如查询方法中所述。下面是一个关于Elasticsearch查询方法的简短示例
例 68 Query creation from method names 从方法名创建查询
interface BookRepository extends Repository<Book, String> {
List<Book> findByNameAndPrice(String name, Integer price);
}
上面的方法名将被翻译成下面的 Elasticsearch json 查询
{
"query": {
"bool" : {
"must" : [
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
]
}
}
}
下面显示了 Elasticsearch 支持的关键字列表。
Supported keywords inside method names 方法名中指出的关键字
Keyword 关键词 | Sample 实例 | Elasticsearch Query String 查询字符串 |
---|---|---|
And | findByNameAndPrice | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } }, { "query_string" : { "query" : "?", "fields" : [ "price" ] } } ] } }} |
Or | findByNameOrPrice | { "query" : { "bool" : { "should" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } }, { "query_string" : { "query" : "?", "fields" : [ "price" ] } } ] } }} |
Is | findByName | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } } ] } }} |
Not | findByNameNot | { "query" : { "bool" : { "must_not" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } } ] } }} |
Between | findByPriceBetween | { "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }} |
LessThan | findByPriceLessThan | { "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : false } } } ] } }} |
LessThanEqual | findByPriceLessThanEqual | { "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }} |
GreaterThan | findByPriceGreaterThan | { "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : false, "include_upper" : true } } } ] } }} |
GreaterThanEqual | findByPriceGreaterThan | { "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } } ] } }} |
Before | findByPriceBefore | { "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }} |
After | findByPriceAfter | { "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } } ] } }} |
Like | findByNameLike | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }} |
StartingWith | findByNameStartingWith | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }} |
EndingWith | findByNameEndingWith | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "*?", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }} |
Contains/Containing | findByNameContaining | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "*?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }} |
In | findByNameIn(Collectionnames) | { "query" : { "bool" : { "must" : [ {"bool" : {"must" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }} |
NotIn | findByNameNotIn(Collectionnames) | { "query" : { "bool" : { "must" : [ {"bool" : {"must_not" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }} |
Near | findByStoreNear | Not Supported Yet ! |
True | findByAvailableTrue | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "true", "fields" : [ "available" ] } } ] } }} |
False | findByAvailableFalse | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "false", "fields" : [ "available" ] } } ] } }} |
OrderBy | findByAvailableTrueOrderByNameDesc | { "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "true", "fields" : [ "available" ] } } ] } }, "sort":[{"name":{"order":"desc"}}] } |
8.1.3. Method return types 方法返回类型
可以将 Repository 方法定义为具有下列返回类型以返回多个元素:
List<T>
Stream<T>
SearchHits<T>
List<SearchHit<T>>
Stream<SearchHit<T>>
SearchPage<T>
8.1.4. Using @Query Annotaion 使用@Query注解
例69 Declare query at the method using the 在方法上使用 @Query
注解
interface BookRepository extends ElasticsearchRepository<Book, String> {
@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
Page<Book> findByName(String name,Pageable pageable);
}
设置为注解参数的字符串必须是有效的Elasticsearch JSON查询。它将作为查询元素的值发送到Easticsearch;例如,如果使用参数John调用该函数,它将生成以下查询体
{
"query": {
"match": {
"name": {
"query": "John"
}
}
}
}
8.2. Annotaion based configuration 基于注解的配置
可以通过JavaConfig使用注解激活Spring Data Elasticsearch repository支持。
例70 Spring Data Elasticsearch repositories using JavaConfig 使用 JavaConfig 的Spring Data Elasticsearh repository
@Configuration
@EnableElasticsearchRepositories( //1
basePackages = "org.springframework.data.elasticsearch.repositories"
)
static class Config {
@Bean
public ElasticsearchOperations elasticsearchTemplate() { //2
// ...
}
}
class ProductService {
private ProductRepository repository; //3
public ProductService(ProductRepository repository) {
this.repository = repository;
}
public Page<Product> findAvailableBookByName(String name, Pageable pageable) {
return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
}
}
- EnableElasticsearchRepositories注解激活repository支持。如果没有配置基本包,它将使用它所在的配置类之一。
- 通过使用在Elasticsearch操作章节中显示的配置之一进行ElasticsearchOperations操作
- 让Spring将repositorybean注入到类中。
8.3. Elasticsearch Repositories using CDI 使用CDI的Elasticsearch repository
Spring Data Elasticsearchrepository也可以使用CDI功能设置。
例71 Spring Data Elasticsearch repositories using CDI
class ElasticsearchTemplateProducer {
@Produces
@ApplicationScoped
public ElasticsearchOperations createElasticsearchTemplate() {
// ... //1
}
}
class ProductService {
private ProductRepository repository; //2
public Page<Product> findAvailableBookByName(String name, Pageable pageable) {
return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
}
@Inject
public void setRepository(ProductRepository repository) {
this.repository = repository;
}
}
- 使用与Elasticsearch操作章节中相同的调用创建组件。
- 让CDI框架将repository注入到类中。
8.4. Spring Namespace 名称空间
Spring Data Elasticsearch模块包含一个自定义名称空间,允许定义repositorybean以及实例化ElasticsearchServer的元素。
如创建repository实例中所述,使用repositories元素查找Spring数据 Data repository。
例 72 Setting up Elasticsearch repositories using Namespace 使用名称空间设置 Elasticsearch repository
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/elasticsearch
https://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
<elasticsearch:repositories base-package="com.acme.repositories" />
</beans>
使用传输客户端或Rest客户端元素在上下文中注册一个Elasticsearch Server实例。
例73 Transport Client using Namespace 使用名称 Transport Client
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/elasticsearch
https://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
<elasticsearch:transport-client id="client" cluster-nodes="localhost:9300,someip:9300" />
</beans>
例 74 Rest Client using Namespace
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch
https://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<elasticsearch:rest-client id="restClient" hosts="http://localhost:9200">
</beans>
8.5. Reactive Elasticsearch Repositories 反应搜索-repository
响应性Elasticsearchrepository支持建立在核心repository支持的基础上,该核心repository支持在使用Spring数据 Data repository时得到了解释,这些数据repository使用响应性客户端执行的响应性Elasticsearch操作提供的操作。
Spring Data Elasticsearch响应式repository支持使用Project Reactor作为其选择的响应式组合库。
有3个主要的接口可以使用:
ReactiveRepository
ReactiveCrudRepository
ReactiveSortingRepository
8.5.1. Usage 用法
要使用repository访问存储在Elasticsearch中的域对象,只需为其创建一个接口。 在实际进行操作之前,您需要一个实体。
例 75 Person entity
public class Person {
@Id
private String id;
private String firstname;
private String lastname;
private Address address;
// … getters and setters omitted
}
请注意,id属性的类型必须是String。
例 76 Basic repository interface to persist Person entities 持久化 Person 实体的基本repository接口
interface ReactivePersonRepository extends ReactiveSortingRepository<Person, String> {
Flux<Person> findByFirstname(String firstname); //1
Flux<Person> findByFirstname(Publisher<String> firstname); //2
Flux<Person> findByFirstnameOrderByLastname(String firstname); //3
Flux<Person> findByFirstname(String firstname, Sort sort); //4
Flux<Person> findByFirstname(String firstname, Pageable page); //5
Mono<Person> findByFirstnameAndLastname(String firstname, String lastname);//6
Mono<Person> findFirstByLastname(String lastname); //7
@Query("{ \"bool\" : { \"must\" : { \"term\" : { \"lastname\" : \"?0\" } } } }")
Flux<Person> findByLastname(String lastname); //8
Mono<Long> countByFirstname(String firstname) //9
Mono<Boolean> existsByFirstname(String firstname) //10
Mono<Long> deleteByFirstname(String firstname) //11
}
- 该方法显示了对具有给定姓的所有人的查询。
- 查找器方法等待来自发布者的输入来绑定firstname的参数值。
- 查找器方法按lastname排序匹配的文档。
- 查找器方法通过Sort参数定义的表达式对匹配的文档进行排序。
- 使用Pageable将偏移量和排序参数传递给数据库。
- 用 and/or 关键字确定条件的查找器方法
- 查找第一个匹配的实体。
- 该方法显示了通过使用运行带注解的@Query查找的具有给定lastname的所有人员的查询
- 计算具有匹配 firstname 的所有实体。
- 检查是否存在至少一个与firstname匹配的实体
- 删除所有具有匹配firstname的条目。
8.5.2. Configutaion 配置
对于Java配置,使用@EnableReactiveElasticsearchRepositories注解。如果没有配置基本包,该基础结构将扫描带注解的配置类的包。
下面的清单显示了如何为repository使用Java配置:
例 77 Java configuration for repositories repository的 Java 配置
@Configuration
@EnableReactiveElasticsearchRepositories
public class Config extends AbstractReactiveElasticsearchConfiguration {
@Override
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
return ReactiveRestClients.create(ClientConfiguration.localhost());
}
}
因为前面示例中的repository扩展了ReactiveSortingRepository,所以可以使用所有CRUD操作以及对实体进行排序访问的方法。使用repository实例是将其注入到客户机中的依赖关系问题,如下面的示例所示
例 78 Sorted access to Person entities 对Person实体的排序访问
public class PersonRepositoryTests {
@Autowired ReactivePersonRepository repository;
@Test
public void sortsElementsCorrectly() {
Flux<Person> persons = repository.findAll(Sort.by(new Order(ASC, "lastname")));
// ...
}
}
9. Auditing 审计
9.1. Basics 基础
Spring Data提供了复杂的支持,以透明地跟踪谁创建或更改了实体以及更改发生的时间。要从该功能中获益,必须为实体类提供审计元数据,这些元数据可以使用注解或通过实现接口定义。
9.1.1. Annotation-based Audition Metadata 基于注解的审计元数据
我们提供@CreatedBy和@LastModifiedBy来捕获创建或修改实体的用户,同时提供@CreatedDate和@LastModifiedDate来捕获更改发生时的用户
例79An audited entity 被审计的实体
class Customer {
@CreatedBy
private User user;
@CreatedDate
private DateTime createdDate;
// … further properties omitted
}
可以看到,可以有选择地应用注解,这取决于您想要捕获的信息。捕获何时进行更改的注解可以用于类型为Joda-Time、DateTime、遗留Java日期和日历、JDK8日期和时间类型以及long或long的属性。
Interface-based Audition Metadata 基于接口的审计元数据
如果不想使用注解定义审计元数据,可以让域类实现Auditable接口。它公开所有审计属性的setter方法。
还有一个方便的基类AbstractAuditable,您可以对它进行扩展,以避免手动实现接口方法。这样做会增加域类与Spring数据的耦合,这可能是您希望避免的。通常,最好使用基于注解的方式定义审计元数据,因为它的侵入性更小,也更灵活。
9.1.3. AuditorAware
在使用@CreatedBy或@LastModifiedBy的情况下,审计基础结构需要知道当前主体。为此,我们提供了一个AuditorAware<T>
SPI接口,您必须实现该接口来告诉基础设施与应用程序交互的当前用户或系统是谁。泛型类型T定义了用@CreatedBy或@LastModifiedBy注解的属性必须是什么类型。
下面的示例展示了使用Spring Security 的身份验证对象的接口实现
例 80 Implementation of AuditorAware based on Spring Secutiry 基于 Spring Secutiry 的 AuditorAeare实现
class SpringSecurityAuditorAware implements AuditorAware<User> {
public Optional<User> getCurrentAuditor() {
return Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getPrincipal)
.map(User.class::cast);
}
}
该实现访问Spring Security提供的身份验证对象,并查找您在UserDetailsService实现中创建的自定义UserDetails实例。我们假设您正在通过UserDetails实现公开域用户,但是根据找到的身份验证,您还可以从任何地方查找它。
9.2. Elasticsearch Audition 稽核
9.2.1. Preparing entities 准备实体
为了让审计代码能够判断一个实体实例是否为新实例,该实体必须实现可持久化的<ID>
接口,该接口定义如下
package org.springframework.data.domain;
import org.springframework.lang.Nullable;
public interface Persistable<ID> {
@Nullable
ID getId();
boolean isNew();
}
由于Id的存在不是一个充分的标准来确定一个enitity是否是新的弹性搜索,额外的信息是必要的。一种方法是对该决策使用与创建相关的审计字段
Person 实体可能看起来如下——为了简洁起见,省略 getter 和 setter 方法:
@Document(indexName = "person")
public class Person implements Persistable<Long> {
@Id private Long id;
private String lastName;
private String firstName;
@Field(type = FieldType.Date, format = DateFormat.basic_date_time)
private Instant createdDate;
private String createdBy
@Field(type = FieldType.Date, format = DateFormat.basic_date_time)
private Instant lastModifiedDate;
private String lastModifiedBy;
public Long getId() { //1
return id;
}
@Override
public boolean isNew() {
return id == null || (createdDate == null && createdBy == null); //2
}
}
- getter也是接口所需的实现
- 如果对象没有id,或者没有设置包含创建属性的字段,则该对象是新对象。
9.2.2. Activating auditing 激活审计
在实体设置好并提供AuditorAware之后,必须通过在配置类上设置@EnableElasticsearchAuditing来激活审计
@Configuration
@EnableElasticsearchRepositories
@EnableElasticsearchAuditing
class MyConfiguration {
// configuration code
}
如果代码包含多个用于不同类型的AuditorAware bean,则必须提供bean的名称,以作为@EnableElasticsearchAuditing注解的auditorAwareRef参数的参数。
10. Entity Callbacks 实体回调
Spring数据基础设施提供了钩子,用于在调用某些方法之前和之后修改实体。那些所谓的EntityCallback实例提供了一种检查和修改回调样式的实体的方便方法。EntityCallback看起来很像专门的ApplicationListener。一些Spring数据模块发布存储允许修改给定实体的特定事件(如BeforeSaveEvent)。在某些情况下,比如使用不可变类型时,这些事件可能会导致麻烦。此外,事件发布依赖于ApplicationEventMulticaste
实体回调提供具有同步和反应api的集成点,以保证在处理链中定义良好的检查点按顺序执行,返回一个可能被修改的实体或反应包装器类型。
实体回调通常由API类型分隔。这种分离意味着同步API只考虑同步实体回调,而反应性实现只考虑反应性实体回调。
实体回调API已经在Spring Data Commons 2.2中引入。这是应用实体修改的推荐方法。现有存储特定的ApplicationEvents仍然在调用可能注册的EntityCallback实例之前发布。
10.1. Implementing Entity Callbacks 实现实体回调
EntityCallback通过其泛型类型参数直接与其域类型关联。每个Spring数据模块通常附带一组预定义的覆盖实体生命周期的EntityCallback接口。
例 81 Anatomy of an EntityCallback
@FunctionalInterface
public interface BeforeSaveCallback<T> extends EntityCallback<T> {
/**
* Entity callback method invoked before a domain object is saved.
* Can return either the same or a modified instance.
*
* @return the domain object to be persisted.
*/
T onBeforeSave(T entity <2>, String collection <3>); //1
}
- 保存实体之前要调用的特定方法。返回一个可能被修改的实例。
- 在持久化之前的实体。
- 许多特定于存储的参数,如实体持久化到的集合。
例82 Anatomy of a reacive EntityCallback
@FunctionalInterface
public interface ReactiveBeforeSaveCallback<T> extends EntityCallback<T> {
/**
* Entity callback method invoked on subscription, before a domain object is saved.
* The returned Publisher can emit either the same or a modified instance.
*
* @return Publisher emitting the domain object to be persisted.
*/
Publisher<T> onBeforeSave(T entity <2>, String collection <3>); //1
}
- 在保存实体之前,在订阅时调用的特定方法。发出一个可能被修改的实例。
- 在持久化之前的实体。
- 许多特定于存储的参数,如实体持久化到的集合。
可选的实体回调参数由实现Spring数据模块定义,并从EntityCallback.callback()的调用站点推断。
实现适合应用程序需要的接口,如下面的示例所示
例 83BeforeSaveCasllBack
class DefaultingEntityCallback implements BeforeSaveCallback<Person>, Ordered { //2
@Override
public Object onBeforeSave(Person entity, String collection) { //1
if(collection == "user") {
return // ...
}
return // ...
}
@Override
public int getOrder() {
return 100; //2
}
}
- 根据您的要求实现回调。
- 如果存在多个相同域类型的实体回调,则可能需要订购实体回调。顺序遵循最低优先级。
10.2. Registering Entity Callbacks 注册实体回调
EntityCallback bean被存储特定的实现拾取,以防它们被注册在ApplicationContext中。大多数模板api已经实现了ApplicationContext,因此可以访问ApplicationContext
下面的示例解释了有效实体回调注册的集合:
例 84 EntityCallback
Bean registration Bean
@Order(1)
@Component
class First implements BeforeSaveCallback<Person> {//2
@Override
public Person onBeforeSave(Person person) {//1
return // ...
}
}
@Component
class DefaultingEntityCallback implements BeforeSaveCallback<Person>,
Ordered {
@Override
public Object onBeforeSave(Person entity, String collection) {
// ...
}
@Override
public int getOrder() {
return 100; //2
}
}
@Configuration
public class EntityCallbackConfiguration {
@Bean
BeforeSaveCallback<Person> unorderedLambdaReceiverCallback() {
return (BeforeSaveCallback<Person>) it -> // ...
}
}
@Component
class UserCallbacks implements BeforeConvertCallback<User>,
BeforeSaveCallback<User> {
@Override
public Person onBeforeConvert(User user) {
return // ...
}
@Override
public Person onBeforeSave(User user) {
return // ...
}
}
- 接收来自@Order注解的订单。
- 通过有序接口实现接收它的订单。
- 使用lambda表达式。默认情况下是无序的,最后调用。注意,由lambda表达式实现的回调不会公开类型信息,因此使用不可分配实体调用这些回调会影响回调吞吐量。使用类或枚举为回调bean启用类型筛选。
- 在一个实现类中组合多个实体回调接口。
10.3. Elasticsearch EntityCallbacks
Spring Data Elasticsearch在内部使用EntityCallback API进行审计支持,并对以下回调做出反应
Supported Entity Callbacks 支持的实体回调
Callback 回调 | Method 方法 | Description 描述 | Order 优先级 |
---|---|---|---|
Reactive/BeforeConvertCallback | onBeforeConvert(T entity, IndexCoordinates index) | Invoked before a domain object is converted to org.springframework.data.elasticsearch.core.document.Document . Can return the entity or a modified entity which then will be converted. | Ordered.LOWEST_PRECEDENCE |
Reactive/AfterConvertCallback | onAfterConvert(T entity, Document document, IndexCoordinates indexCoordinates) | Invoked after a domain object is converted from org.springframework.data.elasticsearch.core.document.Document on reading result data from Elasticsearch. | Ordered.LOWEST_PRECEDENCE |
Reactive/AuditingEntityCallback | onBeforeConvert(Object entity, IndexCoordinates index) | Marks an auditable entity created or modified | 100 |
Reactive/AfterSaveCallback | T onAfterSave(T entity, IndexCoordinates index) | Invoked after a domain object is saved. | Ordered.LOWEST_PRECEDENCE |
11. Miscellaneous Elasticsearch Operation Support 操作支持
本章涵盖了对不能通过repository接口直接访问的Elasticsearch操作的额外支持。建议像Spring数据 Data repository的自定义实现中描述的那样,将这些操作作为自定义实现添加。
11.1. Filter Builder
Filter Builder 提高了查询速度。
private ElasticsearchOperations operations;
IndexCoordinates index = IndexCoordinates.of("sample-index");
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFilter(boolFilter().must(termFilter("id", documentId)))
.build();
Page<SampleEntity> sampleEntities = operations.searchForPage(searchQuery, SampleEntity.class, index);
11.2. Using Scroll For Big Result Set 使用大结果集滚动
有一个可以获得大块结果集的滚动 API。 Spring Data Elasticsearch 在内部使用它来提供<T> SearchHitsIterator<T> SearchOperations.searchForStream(Query query, Class<T> clazz, IndexCoordinates index)
方法的实现。
IndexCoordinates index = IndexCoordinates.of("sample-index");
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFields("message")
.withPageable(PageRequest.of(0, 10))
.build();
SearchHitsIterator<SampleEntity> stream = elasticsearchTemplate.searchForStream(searchQuery, SampleEntity.class, index);
List<SampleEntity> sampleEntities = new ArrayList<>();
while (stream.hasNext()) {
sampleEntities.add(stream.next());
}
stream.close();
在 SearchOperations API 中没有访问滚动 id 的方法,如果需要访问滚动 id,可以使用 ElasticsearchRestTemplate 的以下方法:
@Autowired ElasticsearchRestTemplate template;
IndexCoordinates index = IndexCoordinates.of("sample-index");
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFields("message")
.withPageable(PageRequest.of(0, 10))
.build();
SearchScrollHits<SampleEntity> scroll = template.searchScrollStart(1000, searchQuery, SampleEntity.class, index);
String scrollId = scroll.getScrollId();
List<SampleEntity> sampleEntities = new ArrayList<>();
while (scroll.hasSearchHits()) {
sampleEntities.addAll(scroll.getSearchHits());
scrollId = scroll.getScrollId();
scroll = template.searchScrollContinue(scrollId, 1000, SampleEntity.class);
}
template.searchScrollClear(scrollId);
要将 Scroll API 与 Data repository方法一起使用,返回类型必须定义为 Elasticsearch Repository 中的 Stream。 然后,该方法的实现将使用 ElasticsearchTemplate 中的滚动方法。
interface SampleEntityRepository extends Repository<SampleEntity, String> {
Stream<SampleEntity> findBy();
}
11.3. Sort options 排序选项
除了描述的分页和排序 Spring Data Elasticsearch 的默认排序选项之外,Elasticsearch 还有一个 GeoDistanceOrder 类,可用于根据地理距离排序搜索操作的结果。
如果要检索的类有一个名为 location 的 GeoPoint 属性,下面的 Sort 会根据到给定点的距离对结果进行排序:
Sort.by(new GeoDistanceOrder("location", new GeoPoint(48.137154, 11.5761247)))